设计模式:List-Based Publish-Subscribe

ListBasedPublishSubscribe 示例演示了作为 Windows Communication Foundation (WCF) 程序实现的基于列表的 Publish-Subscribe 模式。

注释

本示例的设置过程和生成说明位于本主题末尾。

基于列表的 Publish-Subscribe 设计模式在 Microsoft 模式和实务出版物《集成模式》中介绍。 Publish-Subscribe 模式将信息传递给已订阅信息主题的收件人集合。 基于列表的发布-订阅可维护一份订户列表。 当有要共享的信息时,会向列表中的每个订阅者发送一个副本。 此示例演示了一种基于动态列表的发布-订阅模式,客户端可以根据需要尽可能频繁地订阅或取消订阅。

基于列表的 Publish-Subscribe 示例由客户端、服务和数据源程序组成。 可以运行多个客户端和多个数据源程序。 客户端订阅服务、接收通知和取消订阅。 数据源程序将信息发送到要与所有当前订阅者共享的服务。

在此示例中,客户端和数据源是控制台程序(.exe 文件),服务是 Internet Information Services(IIS)中托管的库(.dll)。 客户端和数据源活动在桌面上可见。

该服务使用双向通信。 ISampleContract 服务协定与 ISampleClientCallback 回调协定成对出现。 该服务实现订阅和取消订阅操作,客户端使用这些操作来加入或离开订阅者列表。 该服务还实现 PublishPriceChange 服务作,数据源程序调用该服务以向服务提供新信息。 客户端程序实现 PriceChange 服务操作,服务调用该操作以通知所有订阅者价格变动。

// Create a service contract and define the service operations.
// NOTE: The service operations must be declared explicitly.
[ServiceContract(SessionMode=SessionMode.Required,
      CallbackContract=typeof(ISampleClientContract))]
public interface ISampleContract
{
    [OperationContract(IsOneWay = false, IsInitiating=true)]
    void Subscribe();
    [OperationContract(IsOneWay = false, IsTerminating=true)]
    void Unsubscribe();
    [OperationContract(IsOneWay = true)]
    void PublishPriceChange(string item, double price,
                                     double change);
}

public interface ISampleClientContract
{
    [OperationContract(IsOneWay = true)]
    void PriceChange(string item, double price, double change);
}

该服务使用 .NET Framework 事件作为机制来通知所有订阅者有关新信息。 客户端通过调用 Subscribe 加入服务时,会提供事件处理程序。 如果客户端离开,服务将取消其事件处理程序对事件的订阅。 当数据源调用服务来报告价格更改时,该服务将引发该事件。 这会调用服务的每个实例,为每个已订阅的客户端调用一个实例,并导致其事件处理程序执行。 每个事件处理程序通过回调函数将信息传递给其客户端。

public class PriceChangeEventArgs : EventArgs
    {
        public string Item;
        public double Price;
        public double Change;
    }

    // The Service implementation implements your service contract.
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
    public class SampleService : ISampleContract
    {
        public static event PriceChangeEventHandler PriceChangeEvent;
        public delegate void PriceChangeEventHandler(object sender, PriceChangeEventArgs e);

        ISampleClientContract callback = null;

        PriceChangeEventHandler priceChangeHandler = null;

        //Clients call this service operation to subscribe.
        //A price change event handler is registered for this client instance.

        public void Subscribe()
        {
            callback = OperationContext.Current.GetCallbackChannel<ISampleClientContract>();
            priceChangeHandler = new PriceChangeEventHandler(PriceChangeHandler);
            PriceChangeEvent += priceChangeHandler;
        }

        //Clients call this service operation to unsubscribe.
        //The previous price change event handler is unregistered.

        public void Unsubscribe()
        {
            PriceChangeEvent -= priceChangeHandler;
        }

        //Information source clients call this service operation to report a price change.
        //A price change event is raised. The price change event handlers for each subscriber will execute.

        public void PublishPriceChange(string item, double price, double change)
        {
            PriceChangeEventArgs e = new PriceChangeEventArgs();
            e.Item = item;
            e.Price = price;
            e.Change = change;
            PriceChangeEvent(this, e);
        }

        //This event handler runs when a PriceChange event is raised.
        //The client's PriceChange service operation is invoked to provide notification about the price change.

        public void PriceChangeHandler(object sender, PriceChangeEventArgs e)
        {
            callback.PriceChange(e.Item, e.Price, e.Change);
        }

    }

运行示例时,启动多个客户端。 客户端订阅服务。 然后运行数据源程序,该程序将信息发送到服务。 该服务会将信息传递给所有订阅者。 可以在每个客户端控制台上查看活动,确认已收到信息。 在客户端窗口中按 Enter 关闭客户端。

设置和生成示例

  1. 确保已为 Windows Communication Foundation 示例 执行One-Time 安装过程。

  2. 若要生成解决方案的 C# 或 Visual Basic .NET 版本,请按照 生成 Windows Communication Foundation 示例中的说明进行操作。

在同一计算机上运行示例

  1. 通过输入以下地址来测试是否可以使用浏览器访问服务: http://localhost/servicemodelsamples/service.svc 应在响应中显示确认页。

  2. 从 \client\bin\(在语言特定文件夹内)中运行 Client.exe。 客户端活动显示在客户端控制台窗口中。 启动多个客户端。

  3. 从 \datasource\bin\(在语言特定文件夹内)中运行 Datasource.exe。 数据源活动显示在控制台窗口中。 数据源向服务发送信息后,应将其传递给每个客户端。

  4. 如果客户端、数据源和服务程序无法通信,请参阅 WCF 示例的故障排除提示

跨计算机运行示例

  1. 设置服务计算机:

    1. 在服务计算机上,创建名为 ServiceModelSamples 的虚拟目录。 Windows Communication Foundation 示例的一次性安装过程中附带的批处理文件 Setupvroot.bat 可用于创建磁盘目录和虚拟目录。

    2. 将服务程序文件从 %SystemDrive%\Inetpub\wwwroot\servicemodelsamples 复制到服务计算机上的 ServiceModelSamples 虚拟目录。 请务必在 \bin 目录中包括文件。

    3. 测试是否可以使用浏览器从客户端计算机访问服务。

  2. 设置客户端计算机:

    1. 将 \client\bin\ 文件夹中的客户端程序文件(在特定于语言的文件夹下)复制到客户端计算机。

    2. 在每个客户端配置文件中,更改终结点定义的地址值以匹配服务的新地址。 在地址中将任何对“localhost”的引用替换为一个完全限定的域名。

  3. 设置数据源计算机:

    1. 将 \datasource\bin\ 文件夹中的数据源程序文件复制到特定于语言的文件夹下,复制到数据源计算机。

    2. 在数据源配置文件中,更改终结点定义的地址值以匹配服务的新地址。 在地址中将任何对“localhost”的引用替换为一个完全限定的域名。

  4. 在客户端计算机上,从命令提示符启动 Client.exe。

  5. 在数据源计算机上,从命令提示符启动 Datasource.exe。