【发布时间】:2019-12-20 18:44:58
【问题描述】:
我创建了 WCF 服务 (.NET 4.6.2),第三方创建了客户端。
我无法控制客户端,也无法让第三方更改任何内容,因此任何更改都将仅在服务器端进行。
我已将代码最小化并匿名化到最低限度,希望能以尽可能少的代码证明问题。如果我犯了任何错误或您需要任何进一步的细节,我会相应地更改细节。
总结
客户端能够调用服务,解析器能够从 SOAP Action 中正确识别代码中的方法,但是传入的任何对象始终为空。我能够通过断点捕获请求并查看对象在运行时为空。
我已经确定问题主要是由客户端传递的 XML 命名空间前缀引起的。
我能够拦截传入的原始消息,并且可以准确地看到客户端发送的内容。
我能够操作这些传入的消息进行实验,然后将修改后的消息版本发布到服务,以使用基于通用浏览器的客户端测试结果。
示例数据合同:-
[DataContract(Namespace = "http://mycompanyname.co.uk")]
public class SomeObject
{
[DataMember]
public string SomeField { get; set; }
}
服务合同示例:-
[ServiceContract(Namespace = "http://mycompanyname.co.uk")]
public interface IIncoming
{
[OperationContract]
XmlElement MyAction(SomeObject someObject);
}
实现先前定义的服务合同的示例 WCF 服务:-
[ServiceBehavior(Namespace = "http://mycompanyname.co.uk")]
public class Incoming : IIncoming
{
public XmlElement MyAction(SomeObject someObject)
{
XmlDocument response = new XmlDocument();
response.LoadXml("<Response>OK</Response>");
return response.DocumentElement;
}
}
这是第 3 方发布到服务的内容:-
/*3rd party original*/
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns1:MyAction xmlns:ns1="http://mycompanyname.co.uk">
<someObject xmlns="">
<SomeField>Blah</SomeField>
</someObject>
</ns1:MyAction>
</soapenv:Body>
</soapenv:Envelope>
断点代码,可以看到上面的结果是调用了MyAction,但是MyObject为null
我修改了 SOAP 消息以删除空白 xmlns,但 someObject 仍然为空
/*blank xmlns removed*/
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns1:MyAction xmlns:ns1="http://mycompanyname.co.uk">
<someObject>
<SomeField>Blah</SomeField>
</someObject>
</ns1:MyAction>
</soapenv:Body>
</soapenv:Envelope>
我修改了 SOAP 消息以删除 ns1 前缀,但 someObject 仍然为空
/*ns1 removed*/
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<MyAction xmlns="http://mycompanyname.co.uk">
<someObject xmlns="">
<SomeField>Blah</SomeField>
</someObject>
</MyAction>
</soapenv:Body>
</soapenv:Envelope>
现在,如果我同时删除 ns1 前缀和空白 xmlns,那么 someObject 会按预期正确填充。这解决了一切。唯一的问题是,我无法让客户进行此更改。
/*both removed - works*/
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<MyAction xmlns="http://mycompanyname.co.uk">
<someObject>
<SomeField>Blah</SomeField>
</someObject>
</MyAction>
</soapenv:Body>
</soapenv:Envelope>
首先,为什么会发生这种情况?正如我在 XML 中所理解的那样,前缀实际上与确定对象无关,因此 <ns1:Something> 应该与 <ns2:Something> 或 <Something> 相同的对象
然而,WCF 解析器确定 <ns1:Something> 不是 <Something>
如何在服务器端解决这个问题,最好是从 WCF 服务中解决?我在想是否有一种方法可以在 WCF 服务中解析消息之前捕获消息并预先去除 ns1: 和空白 xmlns?
非常感谢
编辑
这是一个示例,您可以复制/粘贴以准确重现问题:-
创建 WCF 服务应用程序 (.NET Framework 4.6.2)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Xml;
namespace GenericIncoming
{
[ServiceContract(Namespace = "http://mycompanyname.co.uk")]
public interface IIncoming
{
[OperationContract]
XmlElement MyAction(SomeObject someObject);
}
[DataContract(Namespace ="")]
public class SomeObject
{
[DataMember]
public string SomeField { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Xml;
namespace GenericIncoming
{
[ServiceBehavior(Namespace = "http://mycompanyname.co.uk")]
public class Incoming : IIncoming
{
public XmlElement MyAction(SomeObject someObject)
{
XmlDocument response = new XmlDocument();
if (someObject != null)
{
response.LoadXml("<Response>OK</Response>");
}
else
{
response.LoadXml("<Response>NULL</Response>");
}
return response.DocumentElement;
}
}
}
运行您的 WCF 服务并将此消息发布到该服务,您将收到“OK”响应
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<MyAction xmlns="http://mycompanyname.co.uk">
<someObject>
<SomeField>Blah</SomeField>
</someObject>
</MyAction>
</s:Body>
</s:Envelope>
现在如果你添加 ns1 前缀,就像第 3 方发送给我一样,那么响应为“NULL”,这意味着 WCF 中的对象为空,因为解析器无法处理 XML
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<ns1:MyAction xmlns:ns1="http://mycompanyname.co.uk">
<someObject>
<SomeField>Blah</SomeField>
</someObject>
</ns1:MyAction>
</s:Body>
</s:Envelope>
这是我无法解决的第一个问题
【问题讨论】: