Поддерживает ли MsmqIntegrationBinding несколько операций службы
Я узнаю о MsmqIntegrationBinding. Все примеры и рекомендации, которые я видел до сих пор, охватывали сценарий, где есть только одна операция с одним контрактом на данные. Я попытался добавить еще один контракт, и сервис успешно запустился. Однако я не могу понять, как достичь второй операции. Возможна ли такая вещь с этой привязкой?
[ServiceContract]
[ServiceKnownType(typeof(Data1))]
[ServiceKnownType(typeof(Data2))]
public interface ISampleService
{
[OperationContract(IsOneWay = true, Action = "*")]
void Operation1(MsmqMessage<Data1> msg);
[OperationContract(IsOneWay = true)]
void Operation2(MsmqMessage<Data2> msg);
}
public class SampleService : ISampleService
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void Operation1(MsmqMessage<Data1> msg)
{
var data = msg.Body;
}
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void Operation2(MsmqMessage<Data2> msg)
{
var data = msg.Body;
}
}
Телефонный код
var queue = new MessageQueue(@".\private$\samplequeue");
var body = new Data1() { Data = "some data" };
var message = new Message(body);
message.Label = "some label";
queue.Send(body, MessageQueueTransactionType.Single);
Это запустит операцию "Операция1", для которой установлено действие "*".
2 ответа
Это очень интересный вопрос.
Действие OperationContractAttribute обычно используется стеком WCF для заполнения заголовков мыла WS-Addressing. Его использование, очевидно, каким-то образом отменено связыванием в очереди.
Возможно, что есть недокументированная особенность WCF, которая позволяет отображать заголовки сообщений msmq в операции на основе атрибута Action, действующего как фильтр, но если есть, я не знаю, какую форму он примет.
Я думаю, что самое простое объяснение: нет, это невозможно, и причина этого в том, что msmqIntegrationBinding - это именно то, что говорится на банке: речь идет о взаимодействии над функциональностью.
Поскольку вы вынуждены вызывать операцию с помощью обертки MsmqMessage, это делает семантически однообразным связывание, и это подтверждает мою теорию о том, что она предназначена для переноса одной операции конечной точки для поддержки взаимодействия с устаревшими клиентами COM и ActiveX.
В любом случае, нет закона, утверждающего, что привязка должна поддерживать несколько операций, точно так же, как некоторые привязки не поддерживают обратные вызовы, а некоторые другие только односторонние операции.
Цени это не отвечает на твой вопрос напрямую.
Не уверен, что это ответ, и у меня нет 50 репутации, чтобы комментировать.
Вдохновившись этим ответом: /questions/7659947/vozmozhno-li-imet-obschij-servis-wcf-dlya-obrabotki-neskolkih-konechnyih-tochek-msmq/7659956#7659956 мы делаем следующее.
[ServiceContract]
public interface IMSMQueueHandler
{
[OperationContract(IsOneWay = true, Action = "*")]
void Handle(MsmqMessage<object> message);
}
Затем у нас есть конструктор класса, оборачивающий хост службы
public MSMQueueServiceHost(IMSMQConfig msmqConfig, IMSMQueueHandler handler)
{
_hostService = new ServiceHost(handler);
AddHostServiceEndPoint(msmqConfig);
_hostService.Open();
}
private void AddHostServiceEndPoint(IMSMQConfig msmqConfig)
{
ServiceMetadataBehavior smb = new ServiceMetadataBehavior { HttpGetEnabled = false };
_hostService.Description.Behaviors.Add(smb);
MsmqIntegrationBinding binding = new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.None);
binding.SerializationFormat = MsmqMessageSerializationFormat.Stream;
binding.ReceiveErrorHandling = ReceiveErrorHandling.Move;
ServiceEndpoint endpoint = _hostService.AddServiceEndpoint(
typeof(IMSMQueueHandler),
binding,
string.Format("msmq.formatname:DIRECT=OS:{0}", msmqConfig.MsmqPath));
// enforce ServiceBehaviours and OperationBehaviours so we dont have to decorate all the handlers
_hostService.Description.Behaviors.Find<ServiceBehaviorAttribute>().InstanceContextMode = InstanceContextMode.Single;
_hostService.Description.Behaviors.Find<ServiceBehaviorAttribute>().ConcurrencyMode = ConcurrencyMode.Single;
AddKnownTypes(endpoint);
}
private static void AddKnownTypes(ServiceEndpoint endpoint)
{
foreach(OperationDescription operation in endpoint.Contract.Operations)
{
operation.KnownTypes.Add(typeof(XElement));
operation.Behaviors.Find<OperationBehaviorAttribute>().TransactionScopeRequired = true;
operation.Behaviors.Find<OperationBehaviorAttribute>().TransactionAutoComplete = true;
}
}
Ключевые строки кода, чтобы заставить его работать:
[OperationContract(IsOneWay = true, Action = "*")]
void Handle(MsmqMessage<object> message);
binding.SerializationFormat = MsmqMessageSerializationFormat.Stream;
operation.KnownTypes.Add(typeof(XElement));
Причиной использования формата Stream является то, что мы видим XML в теле сообщения, заключенном в фигурные скобки (пахнет JSON, но мы не видим причин для этого).
Наконец, и причина, по которой я не уверен, что это ответ, потому что он не использует WCF DataContract и встроенную сериализацию WCF, мы передаем в конструктор обработчик, содержащий следующий метод:
public void Handle(MsmqMessage<object> message)
{
object msmqType = Serializer.Deserialize(message.Body);
_bus.Publish(msmqType);
}
Если это не было очевидно, мы используем сериализацию XML для сообщений.