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

Posted

技术标签:

【中文标题】ServiceContract 对命名空间的定义如何(为啥)影响功能【英文标题】:How (why) definition of Namespace by ServiceContract affects functionalityServiceContract 对命名空间的定义如何(为什么)影响功能 【发布时间】:2019-05-01 11:03:56 【问题描述】:

我有一个这样的 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”。

我在做什么:

    启动网络服务 添加对客户端应用上正在运行的 Web 服务的引用 启动客户端并向服务器发送 SomeEvent。

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

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

更新:

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

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

【问题讨论】:

【参考方案1】:

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

首先我实现了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 无法反序列化事件。

所以问题有两种解决方案

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

【讨论】:

以上是关于ServiceContract 对命名空间的定义如何(为啥)影响功能的主要内容,如果未能解决你的问题,请参考以下文章

4.3 命名空间和程序集

C#中如何获得指定命名空间中所有自定义类的信息

yii2 如何用命名空间方式使用第三方类库

笔录1

第七天

TP框架 命名空间 与第三方类