具有多个操作的Azure SB的WCF订阅者

时间:2015-03-28 19:13:59

标签: c# wcf azure azureservicebus

我正在尝试创建一个WCF服务,它既可以将消息发布到主题,也可以订阅该主题。我的想法是让我的服务公开端点来管理客户(即CreateCustomer,EditCustomer,DeleteCustomer等)。然后我希望它在完成每个操作后向主题发布消息(即OnCustomerCreated,OnCustomerChanged,OnCustomerDeleted等)

例如,客户端应用程序将在我的服务上点击EditCustomer消息。我将立即发布带有客户对象的OnCustomerChanged消息。我的服务(客户点击的那个)将有另一个合同,它接受OnCustomerChanged并更新我的数据库。

我的问题是,我是否必须针对每种消息类型(即OnCustomerChangedSubscription,OnCustomerDeletedSubscription等)针对我的主题单独订阅,以便我可以将不同类型的消息正确路由到正确的端点?

如果是这种情况,我需要一堆单方法合同,以便我可以正确配置wcf端点:

即:

 <service name="site.Services.Business.Managers.CustomerManager">
   <!-- endpoint that clients will hit -->
    <endpoint address="" binding="basicHttpBinding" contract="site.Services.Business.Contracts.ICustomerManager" />
   <!-- endpoint that publishes messages-->
    <endpoint address="sb://test-site.servicebus.windows.net/Managers/CustomerManager" 
              binding="netTcpRelayBinding" 
              contract="site.Services.Business.Contracts.ICustomerManager" 
              behaviorConfiguration="sbTokenProvider" />
    <!-- One Endpoint for each message type (this will get very cumbersome and the contract will only have 1 method on it) -->
    <endpoint address="sb://test-site.servicebus.windows.net/Managers/CustomerManager"
                  binding="netMessagingBinding"
                  listenUri="sb://test-site.servicebus.windows.net/Managers/CustomerManager/subscriptions/OnCustomerDeleted"
                  behaviorConfiguration ="sbTokenProvider"
                  contract="site.Services.Business.Contracts.CustomerManager.IOnCustomerDeleted" />
    <endpoint address="sb://test-site.servicebus.windows.net/Managers/CustomerManager"
                  binding="netMessagingBinding"
                  listenUri="sb://test-site.servicebus.windows.net/Managers/CustomerManager/subscriptions/OnCustomerCreated"
                  behaviorConfiguration ="sbTokenProvider"
                  contract="site.Services.Business.Contracts.CustomerManager.IOnCustomerCreated" />
…etc

  </service>

另一种方法是创建一个订阅者(Allmessages),只有一个HandleMessage(BrokeredMessage message)操作的契约,然后在该方法中使用方法调用我的服务。这似乎并不像我在那里做正确的事情。我基本上接受所有消息并确定服务中的处理程序。

我正在寻找的是一种实现3个合同的服务的方法,ICustomerPublisher(已经有了这个),ICustomerManager(通过http暴露给客户端)和ICustomerSubscriber。

ICustomerSubscriber看起来像:

[ServiceContract]
public interface ICustomerSubscriber
{
    [OperationContract(IsOneWay = true)]
    void OnCustomerCreated(ICustomerMessage message);

    [OperationContract(IsOneWay = true)]
    void OnCustomerDeleted(ICustomerMessage message);

    [OperationContract(IsOneWay = true)]
    void OnCustomerChanged(ICustomerMessage message);
}

我可以致电:

publisher.Publish<OnCustomerChanged>(new CustomerChangedMessage(customer));

让我的OnCustomerChanged方法接收该消息。

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:1)

首先:是的,如果服务具有按请求激活,那么您的SubscriptionClient将无法运行,除非服务响应外部请求,并且每次都必须创建并拆除它。保持SubscriptionClient运行的唯一可行方法是将激活更改为单例。

但我认为更好的方法是将SubscriptionClient完全从这项服务中拉出来并让它自己运行。如果您希望它在本地运行,那么它可以在Windows服务或控制台应用程序中运行;在云中,它可以是WebJob或Worker角色。同样,我不明白为什么你的OnMessage方法需要成为WCF操作。

第二:如果只有一个订阅,则每个消息只能由一个客户端接收和完成。如果多个客户端需要获取每个消息的副本,则每个客户端都需要自己的订阅。订阅可以共享相同的过滤条件,也可以没有条件。

答案 1 :(得分:0)

我无法找到合适的方法来完成我上面提到的内容。相反,我做了以下事情:

创建了我的客户主题的默认订阅,没有过滤器。

在我的WCF服务的构造函数中,我使用SubscriptionClient注册为订阅者:

    public CustomerManager()
    {
        //set up automapper and IoC
        Initializer.Initialize();
        Publisher = IoCContainer.GetContainer().Resolve<IPublisher>("CustomerManager");
        Publisher.Subscribe("AllMessages");

        var client =
            SubscriptionClient.CreateFromConnectionString(CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString"), "customertopic", "AllMessages", ReceiveMode.PeekLock);

        client.OnMessage(m =>
        {
            Console.WriteLine("Message Received.");
            HandleMessage(m);
        });
    }

My HandleMessage方法将BrokeredMessage作为参数,然后根据消息正文类型确定要调用的内部操作。

    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void HandleMessage(BrokeredMessage message)
    {

        var customerMessage = message.GetBody<CustomerMessage>();

        switch (customerMessage.EventName)
        {
            case "OnCreated" : 
                OnCustomerCreated(customerMessage);
                break;
            case "OnDeleted" : 
                OnCustomerDeleted(customerMessage as OnDeleted);
                break;
            case "OnChanged" :
                OnCustomerChanged(customerMessage as OnChanged);
                break;
        }

        message.Complete(); //mark the message as completed

    }

我有几个问题。

首先,我为我的服务使用每个请求配置的实例。这会导致任何类型的消息一致性问题吗?例如,当我有多个CustomerManager实例时,每个实例都会尝试处理相同的消息,或者SubscriptionClient会确保只有1个CustomerManager会收到消息吗?

其次,我希望能够为我的AllMessages订阅订阅其他服务。一个例子是通知服务。我可能希望能够在创建新客户时向帐户所有者发送推送通知(OnCustomerCreated),或者我可能要求客户验证其帐户上更改的信息(OnCustomerChanged)。我是否仍可以将其他服务订阅到CustomerTopic AllMessages,或者将消息标记为完整(正如我在HandleMessage方法结束时那样)清除其他订阅者的消息?从技术上讲,是否会在AllMessages订阅结果中添加另一个订阅者进行多播或平衡?