对XmlElement参数接受简单格式null

时间:2012-02-09 10:49:47

标签: xml wcf null asmx

我正在构建一个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>

1 个答案:

答案 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>