Возможно ли иметь общий сервис WCF для обработки нескольких конечных точек MSMQ?

Наша команда создает сервис для обработки сообщений из нескольких удаленных очередей MSMQ с использованием WCF (через msmqIntegrationBinding). Мы хотели бы иметь возможность регулировать различные группы очередей (через serviceThrottling) в зависимости от количества ресурсов, которые они обычно потребляют.

Моя идея состоит в том, чтобы иметь один тип сервиса, обрабатывающий сообщения из нескольких очередей и определяющий, что с ними делать, основываясь на типе сообщения. К сожалению, я не могу найти общий способ использования MsmqMessage<T> так как он ожидает точного типа сообщения. MsmqMessage<object> не работает, потому что я думаю, что он пытается найти сериализатор для типа object,

Любые идеи о том, как получить эту работу или альтернативные подходы? Предпочтительно все еще использовать WCF, так как он имеет встроенную обработку мертвых букв.

Пример конфигурации:

<services>
    <service name="MessageProcessor.LowResourceMsmqReceiverService" behaviorConfiguration="LowResourceMsmqServiceBehavior">
        <endpoint address="msmq.formatname:DIRECT=OS:.\private$\EmailQueue" binding="msmqIntegrationBinding" bindingConfiguration="IncomingMessageBinding" contract="MessageProcessor.IMsmqReceiverService" />
        <endpoint address="msmq.formatname:DIRECT=OS:.\private$\LoggingQueue" binding="msmqIntegrationBinding" bindingConfiguration="IncomingMessageBinding" contract="MessageProcessor.IMsmqReceiverService" />
    </service>
    <service name="MessageProcessor.HighResourceMsmqReceiverService" behaviorConfiguration="HighResourceMsmqServiceBehavior">
        <endpoint address="msmq.formatname:DIRECT=OS:.\private$\DataImportQueue" binding="msmqIntegrationBinding" bindingConfiguration="IncomingMessageBinding" contract="MessageProcessor.IMsmqReceiverService" />
        <endpoint address="msmq.formatname:DIRECT=OS:.\private$\DataExportQueue" binding="msmqIntegrationBinding" bindingConfiguration="IncomingMessageBinding" contract="MessageProcessor.IMsmqReceiverService" />
    </service>
</services>
<behaviors>
    <serviceBehaviors>
        <behavior name="LowResourceMsmqServiceBehavior">
            <serviceThrottling maxConcurrentCalls="50" />
        </behavior>
        <behavior name="HighResourceMsmqServiceBehavior">
            <serviceThrottling maxConcurrentCalls="3" />
        </behavior>
    </serviceBehaviors>
</behaviors>

Пример контракта:

[ServiceContract]
[ServiceKnownType(typeof(object))]
public interface IMsmqReceiverService
{
    [OperationContract(IsOneWay = true, Action = "*")]
    void Receive(MsmqMessage<object> message);
}

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.PerCall)]
public abstract class TransactionalMsmqReceiverService : IMsmqReceiverService
{
    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    [TransactionFlow(TransactionFlowOption.Allowed)]
    public void Receive(MsmqMessage<object> message)
    {
        // TODO: Handle multiple message types here
    }
}

public sealed class LowResourceMsmqReceiverService : TransactionalMsmqReceiverService { }

public sealed class HighResourceMsmqReceiverService : TransactionalMsmqReceiverService { }

1 ответ

Решение

Проблема на самом деле не была вызвана MsmqMessage<object>,

Когда сообщения в очереди находятся в формате XML, служба использует ServiceKnownTypeAttribute определить, какие типы поддерживаются сервисом для XML (де) сериализации. В этом случае, object на самом деле не является допустимым сериализуемым типом, поэтому он, вероятно, был проигнорирован.

Для поддержки общей обработки сообщений XML вы можете добавить [ServiceKnownType(typeof(XElement))] к вашему контракту на обслуживание и принимаю MsmqMessage<object> в качестве аргумента для вашего метода обслуживания. Это позволит вам проверить свойства MsmqMessage<T> объект, чтобы определить, как это должно быть обработано. Другим возможным вариантом будет использование перегрузки ServiceKnownTypeAttribute который принимает параметр метода для динамического построения списка поддерживаемых типов.

Единственный другой формат сериализации, который я проверил, BinaryИмейте в виду, что все они обрабатываются по-разному. Для Binary формат конкретно нет ServiceKnownTypeAttribute требуется, поскольку информация о типе включена в двоичную полезную нагрузку (проверяется только с System.Guid). Если вы собираетесь использовать Binary формат, важно продолжать использовать MsmqMessage<object> скорее, чем MsmqMessage<XElement> как фактический тип объекта будет проходить вместо XElement,

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