【问题标题】:Contract-First XML attributes (dis)order契约优先 XML 属性 (dis)order
【发布时间】:2016-09-01 12:29:05
【问题描述】:

我遇到了一个奇怪的情况。我正在使用contract-first approach 开发WCF Web 服务。问题是我在 XSD 文件中定义了一个特定的属性顺序,带有标签。尽管如此,使用契约优先工具生成的代码会弄乱这个顺序,当我尝试发送具有指定属性分布的 xml 时,我收到了这个错误(使用 SoapUI 应用程序):

命名空间“http://schemas.datacontract.org/2004/07/InventarioWS.ContractTypes”中的元素“codigoProvinciaField”不是预期的。期待元素“codigoCorporacionField” (从下面的消息翻译)

当我将“codigoCorporacionField”与“codigoProvinciaField”交换时,它会起作用。问题是我在 xml 架构中以相反的方式定义了它们。

似乎没有合同优先的方法,我可以使用[DataMember(Order = 0)] tag

消息:

'http://schemas.datacontract.org/2004/07/InventarioWS.ContractTypes'。 参见 espera el elemento 'codigoCorporacionField'。 Error en la línea 9, posición 42. No se esperaban los elementos 'Element' 'codigoProvinciaField' del espacio de nombres 'http://schemas.datacontract.org/2004/07/InventarioWS.ContractTypes'。 参见 espera el elemento 'codigoCorporacionField'。 zh System.Runtime.Serialization.XmlObjectSerializerReadContext.ThrowRequiredMemberMissingException(XmlReaderDelegator xmlReader, Int32 memberIndex, Int32 requiredIndex, XmlDictionaryString[] memberNames) zh System.Runtime.Serialization.XmlObjectSerializerReadContext.GetMemberIndexWithRequiredMembers(XmlReaderDelegator xmlReader,XmlDictionaryString[] 成员名称,XmlDictionaryString[] memberNamespaces, Int32 memberIndex, Int32 requiredIndex, ExtensionDataObject extensionData) zh ReadCodigoEnteFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] ) zh System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext 上下文) zh System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator 阅读器,字符串名称,字符串 ns,类型声明类型,DataContract& dataContract) zh System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 id, RuntimeTypeHandle 声明TypeHandle, String name, String ns) en ReadEnvioFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] ) zh System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext 上下文) zh System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator 阅读器,字符串名称,字符串 ns,类型声明类型,DataContract& dataContract) zh System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader,类型声明类型,DataContract dataContract,字符串名称, 字符串 ns) zh System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader、布尔型 verifyObjectName、DataContractResolver dataContractResolver) zh System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator 阅读器,布尔验证对象名称,DataContractResolver dataContractResolver) zh System.Runtime.Serialization.DataContractSerializer.ReadObject(XmlDictionaryReader reader, Boolean verifyObjectName) en System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.PartInfo.ReadObject(XmlDictionaryReader 阅读器,XmlObjectSerializer 序列化程序)zh System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeParameterPart(XmlDictionaryReader 阅读器,PartInfo 部分,布尔 isRequest) System.Runtime.Serialization.SerializationException El formateador inició una excepción al intentar deserializar el mensaje: Error al intentar deserializar el 参数http://tempuri.org/:envio。 El mensaje de InnerException 时代 'Error en la línea 9, posición 42. No se esperaban los elementos '元素' 'codigoProvinciaField' del espacio de nombres 'http://schemas.datacontract.org/2004/07/InventarioWS.ContractTypes'。 参见 espera el elemento 'codigoCorporacionField'.'。咨询 InnerException 提供更多信息。

XSD 文件:

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <xsd:element name="Envio">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="Version" type="xsd:string">
        </xsd:element>
        <xsd:element ref="CodigoEnte" minOccurs="1" maxOccurs="1"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element> 

  <xsd:element name="CodigoEnte">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="CodigoComunidad">
          <xsd:simpleType>
            <xsd:restriction base="xsd:string">
              <xsd:length value="2"/>
            </xsd:restriction>
          </xsd:simpleType>
        </xsd:element>
        <xsd:element name="CodigoProvincia">
          <xsd:simpleType>
            <xsd:restriction base="xsd:string">
              <xsd:length value="2"/>
            </xsd:restriction>
          </xsd:simpleType>
        </xsd:element>
        <xsd:element name="CodigoCorporacion">
          <xsd:simpleType>
            <xsd:restriction base="xsd:string">
              <xsd:length value="3"/>
            </xsd:restriction>
          </xsd:simpleType>
        </xsd:element>
        <xsd:element name="Tiporg1">
          <xsd:simpleType>
            <xsd:restriction base="xsd:string">
              <xsd:length value="1"/>
            </xsd:restriction>
          </xsd:simpleType>
        </xsd:element>
        <xsd:element name="Tiporg2">
          <xsd:simpleType>
            <xsd:restriction base="xsd:string">
              <xsd:length value="1"/>
            </xsd:restriction>
          </xsd:simpleType>
        </xsd:element>
        <xsd:element name="Tiporg3">
          <xsd:simpleType>
            <xsd:restriction base="xsd:string">
              <xsd:length value="3"/>
            </xsd:restriction>
          </xsd:simpleType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

</xsd:schema>

以及使用 SoapUI 发送的 XML:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:inv="http://schemas.datacontract.org/2004/07/InventarioWS.ContractTypes">
   <soapenv:Header/>
   <soapenv:Body>
      <tem:RecuperaCorporacionXCodigo>
         <!--Optional:-->
         <tem:envio>
            <inv:codigoEnteField>
               <inv:codigoComunidadField>12</inv:codigoComunidadField>
               <inv:codigoProvinciaField>28</inv:codigoProvinciaField>
               <inv:codigoCorporacionField>022</inv:codigoCorporacionField>
               <inv:tiporg1Field>A</inv:tiporg1Field>
               <inv:tiporg2Field>A</inv:tiporg2Field>
               <inv:tiporg3Field>000</inv:tiporg3Field>
            </inv:codigoEnteField>
            <inv:versionField>?</inv:versionField>
         </tem:envio>
      </tem:RecuperaCorporacionXCodigo>
   </soapenv:Body>
</soapenv:Envelope>

编辑:我忘了说错误来自框架/工具提供的未经请求的字母顺序。在这个answer 中说:

通过以这种方式指定 Order 属性,RegionID 将在生成的架构中出现在 RegionDescription 之前。如果没有此属性,模式中的序列将按字母顺序排序。 Visual Studio 会生成正确的代理,但我不知道你自己的类是什么样子的。确保您的客户端指定相同的 Order 属性。

【问题讨论】:

  • XML 文件中为什么要把 versionField 放在 codigoEnteField 之后? XSD 示意图表明它应该在 codigoEnteField 之前。
  • 你说得对,我改变了这个顺序,但它不影响我之前的错误。
  • 有点离题,但你不应该在元素名称中使用数字。它是合法的 XML,但对于使用它的人来说是可怕的。大多数 XML 开发人员希望能够使用 //inv:tiporg 而不是 //inv:tiporg1、//inv:tiporg2、//inv:tiporg3 等来获取所有的tiporg 字段。
  • 我认为您不会喜欢我提供的解决方法,然后:P。只是出于好奇,为什么建议不要使用数字? xml映射或相关的东西难吗?

标签: c# wcf xsd


【解决方案1】:

我无法解释为什么会出现问题,但我确实认为有一种解决方法。
将 XSD 中的 &lt;xsd:sequence&gt; 替换为 &lt;xs:all&gt;&lt;all&gt; 指示符指定子元素可以按任何顺序出现,并且每个子元素只能出现一次。这应该可以解决您的问题。

【讨论】:

  • 我试过了,问题依旧。此外, xs:all 会修复错误,但也会保持属性无序,这是客户的要求。不过,这是一次不错的尝试。
  • 迭戈是对的。 XML 中的顺序无关紧要,重要的是文档层次结构(包括什么)。
  • 我不同意。如果没关系,为什么我会收到此错误?内部 xml 映射抱怨 System.Runtime.Serialization.XmlObjectSerializerReadContext.ThrowRequiredMemberMissingException。此外,如果您使用 xs:sequence 它需要您定义的相同顺序,而不是 xs:all 标记。这就是为什么我认为 Diego 的回答是有道理的。
  • 有时订单很重要。以 XHTML 为例:例如的顺序出于显而易见的原因,应该尊重文件中的段落。但在许多其他情况下,顺序并不重要或不应该重要;-)
【解决方案2】:

我做了一个解决方法,用“param1...”前缀重命名麻烦的属性。我写这个是为了将来参考,但应该有一个真正的修复。

【讨论】:

    猜你喜欢
    • 2014-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多