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

时间:2018-11-29 11:32:54

标签: c# wcf wsdl

我有一个这样的ServiceContract:

  [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. 启动Web服务
  2. 添加对客户端应用程序上正在运行的Web服务的引用
  3. 启动客户端并将SomeEvent发送到服务器。

这时我遇到了一个问题-将调用后函数,但是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")]),则工作正常

1 个答案:

答案 0 :(得分:0)

好吧,我想,我已经找到了这种现象的原因。

首先,我实现了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 {}添加部分类