问题
Our team is building a service for processing messages from multiple remote MSMQ queues using WCF (via msmqIntegrationBinding). We would like to have the ability to throttle different groups of queues (via serviceThrottling) based on the amount of resources they typically consume.
My idea is to have a single service type processing messages from multiple queues and determining what to do with them based on the type of message. Unfortunately, I can't figure out a generic way to use MsmqMessage<T> as it's expecting the exact type of the message. MsmqMessage<object>
doesn't work because I think it's trying to find a serializer for type object
.
Any ideas on how to get this work or alternative approaches? Preferably still using WCF since it has dead-letter handling already built-in.
Example Configuration:
<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>
Example Contract:
[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:
The issue was not actually caused by MsmqMessage<object>
.
When the queued messages are in XML format, the service uses the ServiceKnownTypeAttribute
to determine what types are supported by the service for XML (de)serialization. In this case, object
isn't really a valid serializable type so it was probably ignored.
In order to support generic processing of XML messages, you can add [ServiceKnownType(typeof(XElement))]
to your service contract and accept MsmqMessage<object>
as the argument to your service method. This will allow you to check properties of the MsmqMessage<T>
object to determine how it should be processed. Another possible option would be to use the overload of the ServiceKnownTypeAttribute
that accepts a method parameter to dynamically build a list of your supported types.
The only other serialization format I checked is Binary
, so keep in mind they are all likely processed differently. For the Binary
format specifically, no ServiceKnownTypeAttribute
is required as the type information is included in the binary payload (only tested this with System.Guid
). If you intend to use the Binary
format, it's important you continue to use MsmqMessage<object>
rather than MsmqMessage<XElement>
as the actual object type will come through instead of XElement
.
来源:https://stackoverflow.com/questions/33152760/is-it-possible-to-have-a-generic-wcf-service-for-handling-multiple-msmq-endpoint