我正在学习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);
这将触发Operation1,其中Action设置为"*"。
我不确定这是不是一个答案,我也没有足够的声望来评论。
从这个答案中得到灵感:https://stackoverflow.com/a/33154517/1095296我们正在做以下事情。
[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));
使用流格式的原因是我们看到消息体中的XML包在大括号中(闻起来像JSON,但我们没有看到为什么)。
最后,我不确定这是一个答案的原因,因为它没有使用WCF DataContract和内置的WCF序列化,我们传递一个包含以下方法的处理程序给构造函数:
public void Handle(MsmqMessage<object> message)
{
object msmqType = Serializer.Deserialize(message.Body);
_bus.Publish(msmqType);
}
如果不是很明显,我们将对消息使用XML序列化。
这是一个非常有趣的问题。
Action OperationContractAttribute通常被WCF栈用来填充WS-Addressing soap报头。它的使用显然在某种程度上被排队绑定覆盖了。
这是可能的,有一个未记录的WCF的功能,允许一些映射的msmq消息头的操作基于动作属性,就像一个过滤器,但如果有,我不知道它会采取什么形式。
我认为最简单的解释是:不,这是不可能的,原因是msmqIntegrationBinding正是它在tin上所说的:它是关于互操作性的功能。
因为你被迫用MsmqMessage包装器调用操作,它使这个绑定在语义上是一维的,这使我的理论,它的目的是包装一个单一的端点操作,以支持与传统COM和ActiveX客户端的互操作。
无论如何,没有法律规定绑定必须支持多个操作,就像某些绑定不支持回调,而其他绑定只支持单向操作一样。
感谢我没有直接回答你的问题。