WCF:数据合同转换为消息合同

时间:2010-08-27 17:53:58

标签: .net wcf datacontract messagecontract

我的WCF服务导出一个操作,标记为catch-all操作和回复操作,以便它代表服务的公共入口点:

[ServiceContract]
public interface IService
{
    [OperationContract (Action="*", ReplyAction="*")]
    Message MyMethod (Message msg);
}

客户端代理仍然是以数据合同生成的。

然而,我发现,尽管客户发送了数据合同,但在msg序列化时,正文似乎与数据合同的等效消息合同而不是数据合同本身。

即使这样也没关系,除了提取内部的数据协定涉及对传入的XML进行手动解析。服务本身没有要使用的实际MessageContract类型,因此访问正文意味着提取节点,重新标记元素等。这是一个手动过程,可能是因为当暴露的操作不是Message时,WCF已经在幕后处理。

WCF在数据合同到数据合同时如何做到这一点?有没有办法可以使用同样的流程?

2 个答案:

答案 0 :(得分:2)

这是正确的默认行为。每次发送请求或响应数据时,它们都会自动包装在包装元素中。它也称为Wrapped参数样式。如果您不想使用它,而是想要使用Bare参数样式,则必须定义消息契约并将其IsWrapped属性设置为false。就像这个简单的例子:

[ServiceContract]
public interface IService
{
    [OperationContract]
    GetMessageResponse GetMessage(GetMessageRequest request);
}

[MessageContract(IsWrapped = false)]
public class GetMessageResponse
{
    [MessageBodyMember]
    public string Result { get; set; }
}

[MessageContract(IsWrapped = false)]
public class GetMessageRequest
{
    [MessageBodyMember]
    public string Data { get; set; }
}

GetMessage操作不会在请求和响应中使用包装。

限制是操作必须只接受单个MessageContract作为参数,并且总是必须返回MessageContract(即使它返回void)。因此,实现您的要求的最简单方法是通过替换属性将所有数据合同转换为消息合同。

另一种方法是为每个请求和响应创建单独的消息协定,并使用数据协定类型的属性作为消息正文。如果由于任何原因你不喜欢为每个操作创建两个额外的消息合同的想法,并且你仍然想要保留旧的数据合同,你可以使用小的黑客(我没有看到任何使用它的原因,但它的工作原理)。将MessageContract属性添加到数据协定,将MessageBodyMember属性添加到所有数据成员。

[DataContract, MessageContract(IsWrapped = false)]
public class MyData
{ 
    [DataMember, MessageBodyMember]
    public string Data { get; set; }
}

答案 1 :(得分:0)

我同意拉迪斯拉夫的看法,你所看到的是正确的行为。 MSDN上有一篇很棒的文档描述了WCF接收和发送消息时发生的事情:

http://msdn.microsoft.com/en-us/library/aa347789.aspx

关于你所问的内容的关键段落在这里:

  

主要使用阅读邮件   由服务框架何时   接收消息。例如,何时   DataContractSerializer正在使用中,   服务框架将获得XML   读者身体并将其传递给   反序列化引擎,它将   然后开始阅读消息   逐个元素和构建   相应的对象图。

因此,框架使用DataContractSerializer将有效负载(这是一个XML信息集)反序列化为接收到的相应类。您可以尝试使用相同的逻辑 - 通过提取有效负载(可能使用返回XmlReader的Message.GetReaderAtBodyContents())然后使用DataContractSerializer将XML反序列化为您要使用返回的{{1 }}

希望这有帮助!