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' 托管。
我在做什么:
- 启动网络服务
- 在客户端应用程序上添加对 运行 网络服务的引用
- 启动客户端并将 SomeEvent 发送到服务器。
此时我遇到了一个问题 - Post-函数将被调用,但是 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")]
)定义了一个命名空间时,那么它 工作正常。
嗯,我想,我已经找到了这种行为的原因。
首先我实现了 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' 节点定义名称空间。所以,我们所拥有的是这个例子中的 xml
是 xmlns="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 {}
添加部分 class
我有一个这样的服务合同:
[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' 托管。
我在做什么:
- 启动网络服务
- 在客户端应用程序上添加对 运行 网络服务的引用
- 启动客户端并将 SomeEvent 发送到服务器。
此时我遇到了一个问题 - Post-函数将被调用,但是 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")]
)定义了一个命名空间时,那么它 工作正常。
嗯,我想,我已经找到了这种行为的原因。
首先我实现了 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' 节点定义名称空间。所以,我们所拥有的是这个例子中的 xml
是 xmlns="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 {}
添加部分 class