Not sure this is an answer and I don't have the required 50 reputation to comment.
Taking inspiration from this answer: https://stackoverflow.com/a/33154517/1095296 we're doing the following.
[ServiceContract]
public interface IMSMQueueHandler
{
[OperationContract(IsOneWay = true, Action = "*")]
void Handle(MsmqMessage<object> message);
}
Then we have a constructor on a class wrapping the service host
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;
}
}
The key lines of code here to make it work are:
[OperationContract(IsOneWay = true, Action = "*")]
void Handle(MsmqMessage<object> message);
binding.SerializationFormat = MsmqMessageSerializationFormat.Stream;
operation.KnownTypes.Add(typeof(XElement));
The reason for the Stream format is we were seeing the XML in the message body wrapped in braces (smells like JSON but we saw no reason why).
Finally, and the reason I'm not sure this is an answer because it's not using a WCF DataContract and the built-in WCF serialization, we pass a handler containing the following method to the constructor:
public void Handle(MsmqMessage<object> message)
{
object msmqType = Serializer.Deserialize(message.Body);
_bus.Publish(msmqType);
}
If it wasn't obvious, we're using XML serialization for the messages.