2

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

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

客户端代理仍然作为数据合约生成。

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

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

当它是数据合同到数据合同时,WCF 如何做到这一点?有没有办法可以使用相同的过程?

4

2 回答 2

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)。因此,实现您的要求的最简单方法是通过替换属性将所有数据合约转换为消息合约。

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

[DataContract, MessageContract(IsWrapped = false)]
public class MyData
{ 
    [DataMember, MessageBodyMember]
    public string Data { get; set; }
}
于 2010-08-27T23:29:54.010 回答
0

我同意 Ladislav 的观点,即您所看到的是正确的行为。MSDN 上有一个很棒的文档,描述了 WCF 接收和发送消息时发生的情况:

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

与您要问的内容相关的关键段落在这里:

读取消息主要由服务框架在接收消息时使用。例如,在使用 DataContractSerializer 时,服务框架将通过正文获取 XML 读取器并将其传递给反序列化引擎,然后反序列化引擎将开始逐个元素地读取消息并构造相应的对象图。

因此,框架在DataContractSerializer接收到有效负载(它是一个 XML 信息集)时使用 a 将其反序列化为适当的类。您可以尝试使用相同的逻辑 - 通过提取有效负载(可能使用Message.GetReaderAtBodyContents()它返回 XmlReader),然后使用 DataContractSerializer 将 XML 反序列化为您想要使用返回的对象XmlReader

希望这会有所帮助!

于 2010-08-28T00:03:07.697 回答