Поддерживает ли 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 для сообщений.

Другие вопросы по тегам