我正在尝试创建一个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方法接收该消息。
任何帮助都将不胜感激。
答案 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订阅结果中添加另一个订阅者进行多播或平衡?