为什么 WCF 将请求/响应类型包装在另一个 XML 元素中,以及如何防止这种情况发生?

发布于 2024-07-27 05:11:05 字数 2425 浏览 5 评论 0 原文

我有一个简单的 echo 服务,其中定义了一个操作方法和一对请求/响应类型:

[ServiceContract(Name = "EchoService", 
                 Namespace = "http://example.com/services", 
                 SessionMode = SessionMode.NotAllowed)]
public interface IEchoService
{
    [OperationContract(IsOneWay = false,
                       Action = "http://example.com/services/EchoService/Echo", 
                       ReplyAction = "http://example.com/services/EchoService/EchoResponse")]
    EchoResponse Echo(EchoRequest value);
}

数据类型:

[Serializable]
[DataContract(Namespace = "http://example.com/services/EchoService", 
              Name = "EchoRequest")]
public class EchoRequest
{
    public EchoRequest() { }

    public EchoRequest(String value)
    {
        Value = value;
    }

    [DataMember]
    public String Value { get; set; }
}

[Serializable]
[DataContract(Namespace = "http://example.com/services/EchoService", 
              Name = "EchoResponse")]
public class EchoResponse
{
    public EchoResponse() { }

    public EchoResponse(String value)
    {
        Value = value;
    }

    [DataMember]
    public String Value { get; set; }
}

在 EchoRequest 实例上调用 Message.CreateMessage() 会产生:

  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header />
    <s:Body>
      <EchoRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.com/services/EchoService">
        <Value>hello, world!</Value>
      </EchoRequest>
    </s:Body>
  </s:Envelope>

...这正是我想要的。 但是,该服务似乎希望将消息正文进一步包装在另一个 XML 元素中,如下所示:

  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header />
    <s:Body>
      <Echo xmlns="http://example.com/services">
        <EchoRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.com/services/EchoService">
          <Value>hello, world!</Value>
        </EchoRequest>
      </Echo>
    </s:Body>
  </s:Envelope>

更新: 感谢 Mark 的回复,我在请求/响应类型上探索了 MessageContract 而不是 DataContract。 这似乎更接近我想要的,但现在它太过分了,并且不期望外部类型元素“EchoRequest”。

这很令人困惑,因为不知何故 Message.CreateMessage 似乎总是能够生成正确的 XML,因此它显然使用了一些默认的序列化,我希望将服务配置为接受。 我只是误解了 Message.CreateMessage 的工作原理吗?

I have a simple echo service where I've defined one operation method and a pair of types for request/response:

[ServiceContract(Name = "EchoService", 
                 Namespace = "http://example.com/services", 
                 SessionMode = SessionMode.NotAllowed)]
public interface IEchoService
{
    [OperationContract(IsOneWay = false,
                       Action = "http://example.com/services/EchoService/Echo", 
                       ReplyAction = "http://example.com/services/EchoService/EchoResponse")]
    EchoResponse Echo(EchoRequest value);
}

The data types:

[Serializable]
[DataContract(Namespace = "http://example.com/services/EchoService", 
              Name = "EchoRequest")]
public class EchoRequest
{
    public EchoRequest() { }

    public EchoRequest(String value)
    {
        Value = value;
    }

    [DataMember]
    public String Value { get; set; }
}

[Serializable]
[DataContract(Namespace = "http://example.com/services/EchoService", 
              Name = "EchoResponse")]
public class EchoResponse
{
    public EchoResponse() { }

    public EchoResponse(String value)
    {
        Value = value;
    }

    [DataMember]
    public String Value { get; set; }
}

Invoking Message.CreateMessage() on an instance of EchoRequest yields:

  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header />
    <s:Body>
      <EchoRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.com/services/EchoService">
        <Value>hello, world!</Value>
      </EchoRequest>
    </s:Body>
  </s:Envelope>

...which is exactly what I want. However, it appears that the service is expecting the message body to be further wrapped in another XML element, like this:

  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header />
    <s:Body>
      <Echo xmlns="http://example.com/services">
        <EchoRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.com/services/EchoService">
          <Value>hello, world!</Value>
        </EchoRequest>
      </Echo>
    </s:Body>
  </s:Envelope>

UPDATE:
Thanks to Mark's reply, I've explored MessageContract instead of DataContract on the request/response types. This seems closer to what I want, but now it's going too far, and not expecting the outer type element, "EchoRequest".

This is confusing since somehow Message.CreateMessage appears to unfailingly produce the correct XML, so it's apparently using some default serialization which I'd like to configure the service to accept. Am I just misunderstanding how Message.CreateMessage works?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

她说她爱他 2024-08-03 05:11:05

IIRC、WCF 默认情况下使用“Wrapped”消息样式。 如果您希望能够控制消息的序列化方式,可以通过使用 MessageContractAttribute。 对于显式消息协定,您可以设置 IsWrapped 属性设置为 false

在你的情况下,我认为 EchoRequest 和 EchoResponse 根本不应该是 DataContracts,而应该是 MessageContracts。 对我来说,它们看起来很像 MessageContracts。

IIRC, WCF by default uses the 'Wrapped' message style. If you want to be able to control how messages are serialized, you can define explicit messages by decorating with the MessageContractAttribute. With explicit message contracts, you can set the IsWrapped property to false.

In your case I think that EchoRequest and EchoResponse shouldn't be DataContracts at all, but rather MessageContracts. They look a lot like MessageContracts to me.

鹿港巷口少年归 2024-08-03 05:11:05

我最终转而使用 消息合约,使用 TypedMessageConverter 我是通过 这个问题的答案。 这就是这里缺失的部分。

I eventually switched over to use Message Contracts using a TypedMessageConverter which I was introduced to via this question's answer. That was the missing piece here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文