如何修复Visual Studio生成的用于处理锯齿状数组的Web引用代理?

时间:2010-08-06 13:50:14

标签: .net web-services xsd xml-serialization wsdl

似乎wsdl.exe中存在一个已知错误,即Visual Studio用于生成Web服务代理的工具。使用某些XSD架构,该工具将生成无法从XML反序列化的类。

据我所知,这是不可接受的,但我不知道如何解决它。

我将详细描述我的案例,希望有人能够帮助我。

模式

<!-- return type from the service operation -->
<xs:complexType name="listAssetsQueryResults">
    <xs:sequence>
        <xs:element name="assets" type="tns:asset" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:complexType>

<!-- a sequence of attributes -->
<xs:complexType name="asset">
    <xs:sequence>
        <xs:element name="attributes" type="tns:multiValuedAttribute" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:complexType>

<xs:complexType name="multiValuedAttribute">
    <!-- not relevant-->
</xs:complexType>

来自网络服务的XML响应

根据此架构的典型响应如下所示:

<assets-query-result>
    <assets>
        <attributes>
            <name>Keywords</name>
            <values>Desert</values>
        </attributes>
        <attributes>
            <name>Filename</name>
            <values>Desert.jpg</values>
        </attributes>
    </assets>
    <assets>...</assets>
    <assets>...</assets>
</assets-query-result>

使用代码中的类型

我原本希望能够使用这样的CLR类型:

result.assets[0].attributes[0].name

相反,生成的结果类型如下所示:

[SerializableAttribute()]
public partial class listAssetsQueryResults {
    private multiValuedAttribute[][] assetsField;

    [XmlArrayAttribute(Form=XmlSchemaForm.Unqualified, IsNullable=true)]
    [XmlArrayItemAttribute("attributes", typeof(multiValuedAttribute), Form=XmlSchemaForm.Unqualified)]
    public multiValuedAttribute[][] assets {
        get { return this.assetsField; }
        set { this.assetsField = value; }
    }
}

甚至不允许生成序列化程序集!

  

无法转换类型   Portfolio.WebService.multiValuedAttribute   到Portfolio.WebService.multiValuedAttribute []

修复

1 - 更改属性和字段的类型

现在,我在网上找到的修复之一就是从生成的属性类型中删除一对括号:

// No longer a jagged array, but this doesn't deserialize all data
public multiValuedAttribute[] assets;

这允许构建序列化程序集,并且它无异常地运行,除了它没有正确地序列化数据,它“跳过”资产列表并反序列化第一个assets元素的属性。所以它根本不是修复,因为有了这个修复,我无法使用数据。对于700多个资产,它result.assets等于multiValuedAttribute[2](2个元素是第一个资产的名称和关键字属性)。

2 - 指定XML元素的类型

我尝试的第二件事是给反序列化器提供不同的指令:

[XmlArrayItemAttribute("attributes", typeof(multiValuedAttribute[]), Form=XmlSchemaForm.Unqualified)]
public multiValuedAttribute[][] assets { ... }

所以现在我告诉它序列中的每个元素都是multiValuedAttribute[]类型。这是错误的,因为它仍然在查看attributesmultiValuedAttribute类型的元素(单个,不是数组)。但确实会运行,但现在result.assets等于multiValuedAttribute[2][0],我仍然无法获取数据。

下一步是什么?

我不知道,这就是我写这个的原因。我无法接受.NET无法使用此Web服务,因为它必须这样做。

3 个答案:

答案 0 :(得分:3)

我认为您应该定义一个具有multiValuedAttribute []类型属性的单独Asset类。所以它会像

public class Asset
{
   public multiValuedAttribute[] attributes {get; set;}
}

public partial class listAssetsQueryResults {
    private Asset[] assetsField;

    public Asset[] assets {

然后你需要装饰资产类型,属性和&amp; assets属性与XmlElement / XmlArrayElement / XmlArrayItemElement属性的某种组合,以使其工作。

毋庸置疑,只要您需要重新生成代理代码,就必须重新应用上述更改(也许您可以将其作为构建操作制作批处理脚本)。

答案 1 :(得分:2)

当使用用Java编写然后由WCF,C#,。Net等使用的SOAP Web服务时,这个问题非常典型,其中使用了锯齿状数组(数组数组)。 VinayC的帖子有所帮助,但这里有一些更明确的代码可以帮助遇到这个问题的其他人。

请注意,这些类是缩写的。您的WSDL生成的代码肯定会看起来更复杂。

public partial class assests{
  private multiValuedAttribute[] attributesField;
  [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
  public multiValuedAttribute[] attributes{
    get {return this.attributesField;}
    set {this.attributesField = value;}
  }
}

public partial class listAssetsQueryResults{
  private assests[] assetsField;
  [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
  public assets[] assets{
      get {return this.assetsField;}
      set {this.assetsField = value;}
  }
}

这里的关键是创建一个新的'assets'类,它是multiValuedAttribute和listAssetsQueryResults类之间的链接,然后使用XmlElementAttribute序列化该字段。在您自己的项目中执行此操作的一种好方法是首先复制并粘贴类似于multiValuedAttribute类的类(尽管此类实现未在此处显示)。然后,只需将复制的multiValuedAttribute类重命名为“assets”并更改实现,以便它可以作为两者之间的链接。删除listAssetsQueryResults类中包含[] []的语句中的extra []。使用XmlElement而不是XmlArrayItem进行序列化。

当然,不同的服务有不同的要求。 Fiddler应用程序(http://fiddler2.com/)可以真正帮助检查序列化,以确保你做对了。 Fiddler确实帮助了我。以下是一些帮助我的额外阅读:http://msdn.microsoft.com/en-us/library/2baksw0z.aspx

答案 2 :(得分:0)

您可以随时更改类型,以便Web服务向wsdl处理器返回友好的内容。因此,例如,根据您提供的示例,您应该能够轻松地将其转换为KeyValuePair<string, string>或其他类似的数组,然后再从Web服务返回它。

这可能是比暴露锯齿状数组更好的API。

  

我无法接受.NET无法接受   使用此Web服务

好吧,正如我的朋友特蕾莎修女所说:“生活是一场斗争,接受它。” ; - )