我正在构建一个WCF服务(.Net 3.5,IIS Hosted)来替换旧的ASMX样式服务。它必须非常与旧式界面兼容,以避免编写调用它的软件的供应商付出努力。 (其中一些构建了一个简单的XML数据结构,将其放入预先准备好的SOAP“模板”中并将其抛给我的服务。我需要接受他们的现有的 XML结构。)
为了兼容这些客户端调用服务的方式,我必须将操作定义为:
[ServiceContract(Namespace = "urn:namespacex")]
public interface IServices
{
[OperationContract]
System.Xml.XmlElement OperationA(int parmB, System.Xml.XmlElement parmC);
}
即。参数位于OperationContract中,而不是拉入DataContract中的单独DataMember元素。此处使用的XmlElement替换了旧ASMX服务中使用的XmlNode参数。
它实现为:
[ServiceBehavior(Namespace = "urn:namespacey")]
public class TheService : IServices
{
public System.Xml.XmlElement OperationA(int parmB, System.Xml.XmlElement parmC)
{
... code to handle call
}
}
当有数据要发送时,它工作正常。
我遇到的问题是当parmC输入为空时,这是允许的。有时它有数据,有时却没有。一个调用者在SOAP消息中发送一个null parmC:
<parmC/>
即。一个简单的空XML元素。
这会从WCF引发以下错误:
期待状态'元素'..遇到名称的'EndElement' 'parmC',命名空间'urn:namespacex'。
所以它似乎不喜欢简单的null元素输入。 (如果那里有实际的数据,该服务可以正常工作。)
跟踪我自己的测试调用者(在parmC参数中使用和不使用信息),我可以看到对于null我的(.Net WCF)测试人员正在发送:
<parmC xmlns:i="http://www.w3.org/2001/XMLSchema-instance" i:nil="true"/>
尝试1:
寻求帮助,我注意到“[XmlSerializerFormat]”属性应该通过不使用较新的数据协定序列化程序使服务更像旧式ASMX。我的测试调用者(.Net,WCF)然后根本不发送任何null。但是这个客户端仍然会收到一个错误,尽管它现在是一个不同的消息,参考该元素:
没有相应的开始元素打开。
尝试2:
然后我记得原始ASMX服务的最旧版本使用字符串来接受该数据。 (它将该字符串加载到XML对象服务器端,在操作的处理程序中)。所以我更改了合同和操作,将parmC定义为字符串,而不是XmlElement。
突然,该服务正在接受各种形式的空parmC。 (使用快速测试应用程序将原始SOAP发布到我的服务,因此我可以模拟这些供应商的行为)。
但是 - 如果其中存在实际数据,则会失败,但是:
反序列化操作请求消息正文时出错 'OperatonA'。 ---&GT; System.InvalidOperationException:出错 在XML文档中(99,99)。 ---&GT; System.Xml.XmlException:结束元素 命名空间'urn:namespacex'的'parmC'。找到元素'a' 来自命名空间''
(当在parmC中发送XML数据时,它在SOAP中看起来像这样:
<parmC>
<a xmlns="">bbb</a>
</parmC>
)
显然,在这种情况下,不希望在字符串中找到XML('a'元素);但这曾经在ASMX中工作,所以“值得一试”。
所以我找不到允许将XML数据发送到服务的设置组合,同时还允许客户端样式为空数据或空数据。
我是否必须实施自定义反序列化器?某个地方是否有帮助?
(到目前为止,我已经设法将WCF的所有内容完全保留在配置中,如果可以,我希望保持这种方式。)
总之,我需要一个WCF服务来处理这些中的任何一个:
<s:Body>
<OperationA xmlns="urn:namespacex">
<parmB>1</parmB>
<parmC> { this works fine }
<a xmlns="">
<b>bbb</b>
</a>
</parmC>
</OperationA>
</s:Body>
<s:Body>
<OperationA xmlns="urn:namespacex">
<parmB>1</parmB>
<parmC/> { I need this to be accepted }
</OperationA>
</s:Body>
答案 0 :(得分:1)
您提供的两个选项的XML是不等效。两者之间存在非常微妙的差异,这可能是导致问题的原因。 <a xmlns="">
选项将 a 元素及其子元素设置为没有默认的 XML命名空间。另一个选项(“null”参数选项)不包含默认XML命名空间的“重新定义”,从“urn:namespacex”到“”,因此当反序列化过程解析parmC for element <a xmlns="">
时它无法找到它。如果您仔细阅读了异常消息,它实际上是在告诉您。
至于如何支持这两种方案,请尝试让您的客户端发送此内容而不是现在发送的内容:
<parmC>
<a xmlns="">
<b />
</a>
</parmC>
或可能:
<parmC>
<a xmlns="" />
</parmC>