ServiceContract 对命名空间的定义如何(为什么)影响功能

How (why) definition of Namespace by ServiceContract affects functionality

我有一个这样的服务合同:

  [ServiceContract]
  public interface IHttpsServer
  {
    [OperationContract] 
    [XmlSerializerFormat]
    void Post(SomeEvent e);
  }

事件定义如下:

  [Serializable]
  [XmlType(Namespace = "")]
  public class SomeEvent 
  {
    [XmlAttribute("flag")]
    public bool m_bFlag;

    [XmlElement("Name")]
    public string m_strName;
    ...
  }

此服务由 ServiceHost 和 'BasicHttpBinding' 托管。

我在做什么:

  1. 启动网络服务
  2. 在客户端应用程序上添加对 运行 网络服务的引用
  3. 启动客户端并将 SomeEvent 发送到服务器。

此时我遇到了一个问题 - Post-函数将被调用,但是 SomeEvent 是空的(所有可为空的字段都是 null)。

但是,如果我给 ServiceContrat ([ServiceContract(Namespace = "")]) 一个空的命名空间,那么它工作正常。 为什么会这样?

更新:

我已经执行了几项检查,但结果都很奇怪:

  1. 当 ServiceContract 和 SomeEvent([ServiceContract(Namespace = "http://anynamespace")][XmlType(Namespace = "http://othernamespace")])定义命名空间时,它 工作正常
  2. 当命名空间仅由 ServiceContract([ServiceContract(Namespace = "http://anynamespace")][XmlType(Namespace = "")])定义时,不起作用
  3. 当([ServiceContract(Namespace = "")][XmlType(Namespace = "")])都定义了一个空命名空间时,工作正常
  4. 当 ServiceContract 有一个空命名空间,但为 SomeEvent([ServiceContract(Namespace = "")][XmlType(Namespace = "http://othernamespace")])定义了一个命名空间时,那么它 工作正常

嗯,我想,我已经找到了这种行为的原因。

首先我实现了 IDispatchMessageInspector。这使我有可能跟踪来自客户的请求。 来自客户端的请求如下所示:

+       request {<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">https://localhost/</To>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IHttpsServer/Post</Action>
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Post xmlns="http://tempuri.org/">
      <xml flag="true">
        <Name>John</Name>
      </xml>
    </Post>
  </s:Body>
</s:Envelope>}  System.ServiceModel.Channels.Message {System.ServiceModel.Channels.BufferedMessage}

一段时间后我注意到,为 Post 节点定义了一个默认名称空间,而没有为 'xml' 节点定义名称空间。所以,我们所拥有的是这个例子中的 xmlxmlns="http://tempuri.org/" 的一部分,而不是它定义的空命名空间。

为了检查我的建议,我生成了客户端代码并手动添加了一个 XmlType 属性到 SomeEvent:

的声明中
  [System.Xml.Serialization.XmlType(Namespace = "")]

此更改后我得到了以下请求:

+       request {<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">https://localhost/</To>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IHttpsServer/Post</Action>
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Post xmlns="http://tempuri.org/">
      <xml flag="true">
        <Name xmlns="">John</Name>
      </xml>
    </Post>
  </s:Body>
</s:Envelope>}  System.ServiceModel.Channels.Message {System.ServiceModel.Channels.BufferedMessage}

Name节点定义了默认命名空间)。

之后我的服务工作正常。

我对问题原因的建议:

如果我为事件 [XmlType(Namespace = "")]public class SomeEvent {...} 定义了空命名空间,则在生成客户端代码时将跳过属性 XmlType。当请求被发送时,描述该事件的 xml 被放置在 ServiceContract 的命名空间中。之后 WCF 无法反序列化事件。

所以这个问题有两种解法:

  1. 避免使用具有空命名空间的事件(参见用例 2)。
  2. 为事件 [XmlType(Namespace = "")]public partial class SomeEvent {}
  3. 添加部分 class