2010-08-06 2 views
5

Es scheint, dass es einen bekannten Fehler in wsdl.exe gibt, dem Tool, das Visual Studio verwendet, um Web-Service-Proxies zu generieren. Bei bestimmten XSD-Schemas generiert das Tool Klassen, die nicht aus dem XML-Code deserialisiert werden können.Wie kann ich den Web-Referenz-Proxy reparieren, den Visual Studio zur Verarbeitung von gezackten Arrays generiert hat?

Soweit es mich betrifft, das ist inakzeptabel, aber ich weiß nicht, wie man es beheben kann.

Ich werde meinen Fall im Detail beschreiben, hoffentlich wird mir jemand dabei helfen können.

Schema

<!-- 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-Antwort von der WebService

Eine typische Reaktion auf dieses Schema entsprechend sieht wie folgt aus:

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

die Typen im Code verwenden

ich hätte anknüpfen können die CLR-Typen wie folgt verwenden:

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

Stattdessen sieht der erzeugte Typ für das Ergebnis wie folgt aus:

[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; } 
    } 
} 

die nicht einmal tut erlauben Sie, dass die Serialisierungsassembly erzeugt wird!

Unable Typ konvertieren Portfolio.WebService.multiValuedAttribute zu Portfolio.WebService.multiValuedAttribute []

Fixing es

1 - Ändern der Art der Immobilie und Feld

Eine der Korrekturen, die ich online gefunden habe, ist einfach, ein Paar Klammern vom Typ des Gen zu entfernen erated Eigenschaft:

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

Das ist die Serialisierungsassembly gebaut werden können, und es läuft ohne Ausnahmen, außer es die Daten nicht richtig serialisiert, es springt "die Liste der Vermögenswerte und deserialisiert die Attribute des ersten assets Element. Es ist also überhaupt keine Lösung, denn mit dieser Lösung kann ich die Daten nicht konsumieren. Für 700+ Assets gibt es result.assets ist gleich multiValuedAttribute[2] (die 2 Elemente sind die Attribute name und keywords des ersten Assets).

2 - Angabe der Art der XML-Elemente

Das zweite, was ich versuchte, ist die Deserializer verschiedene Anweisungen zu geben:

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

So, jetzt sage ich es, dass jedes Element in der Sequenz ist vom Typ multiValuedAttribute[].Das ist falsch, weil es immer noch attributes Elemente betrachtet, die vom Typ multiValuedAttribute (single, kein Array) sind. Es läuft aber, aber jetzt ist die result.assets gleich multiValuedAttribute[2][0] und ich bin immer noch nicht in der Lage, zu den Daten zu gelangen.

Was kommt als nächstes?

Ich habe keine Ahnung, weshalb ich das geschrieben habe. Ich kann nicht akzeptieren, dass .NET diesen Webdienst nicht nutzen kann, weil er es muss.

+0

Haben Sie jemals eine bessere Lösung dafür gefunden? Ich bin mit dem genauen Problem konfrontiert, aber ich habe Hunderte von Typen, die geändert werden müssten –

Antwort

3

Ich denke, dass Sie eine separate Asset-Klasse definieren sollten, die eine Eigenschaft vom Typ multiValuedAttribute [] haben würde. So wäre es so etwas wie

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

public partial class listAssetsQueryResults { 
    private Asset[] assetsField; 

    public Asset[] assets { 

geht Dann brauchen Sie Anlagentyp dekorieren, Attribute & Vermögen Immobilien mit einer Kombination aus XmlElement/XmlArrayElement/XmlArrayItemElement Attributen es zum Laufen zu bringen.

Unnötig zu erwähnen, dass Sie den Proxy-Code jederzeit neu generieren müssen, wenn Sie die obigen Änderungen erneut anwenden müssen (vielleicht können Sie dafür ein Batch-Skript als Build-Aktion erstellen).

0

Sie könnten den Typ immer ändern, so dass der Webservice etwas freundliches zum WSDL-Prozessor zurückgibt. Zum Beispiel, basierend auf dem Beispiel, das Sie angegeben haben, sollten Sie es leicht in ein Array von KeyValuePair<string, string> oder etwas konvertieren können, bevor Sie es vom Web-Service zurückgeben.

Dies ist wahrscheinlich eine bessere API als exponierte gezackte Arrays.

ich nicht, dass die .NET akzeptieren kann, ist nicht fähig, diese Web-Service zu konsumieren

Nun, wie mein Freund Mutter Teresa sagt: „Das Leben ist ein Kampf, es zu akzeptieren.“ ;-)

+1

Ich kann den Web-Service nicht ändern, es ist Teil der Server-Software, die wir gekauft haben. Das ist auch der Grund, warum ich nicht akzeptieren kann, dass ich den Web-Service nicht konsumieren kann. Ich muss einfach mit dem arbeiten, was ich habe. –

2

Dieses Problem ist sehr typisch beim Konsum von SOAP-Webdiensten, die in Java geschrieben wurden und dann von WCF, C#, .Net usw. verwendet wurden, wo gezackte Arrays (Arrays von Arrays) verwendet wurden. Der Post von VinayC hat geholfen, aber hier ist ein etwas expliziterer Code, der zum Beispiel anderen helfen kann, die dieses Problem haben.

Beachten Sie, dass diese Klassen abgekürzt sind. Ihr WSDL-generierter Code wird sicherlich komplexer aussehen.

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;} 
    } 
} 

Der Schlüssel hier ist eine neue ‚Assets‘ Klasse zu erstellen, die eine Verbindung zwischen multiValuedAttribute und listAssetsQueryResults Klassen ist, und dann das Feld XmlElementAttribute mit serialisiert. Eine gute Möglichkeit, dies in Ihren eigenen Projekten zu tun, besteht darin, die Klasse zu kopieren und einzufügen, die der multiValuedAttribute-Klasse entspricht (obwohl diese Klassenimplementierung hier nicht gezeigt wird). Benennen Sie dann die kopierte multiValuedAttribute-Klasse einfach als "Assets" um und ändern Sie die Implementierung so, dass sie stattdessen als eine Verknüpfung zwischen den beiden fungiert. Entfernen Sie das Extra [] in den Anweisungen, die [] [] in der listAssetsQueryResults-Klasse enthalten. Serialisieren Sie mit XmlElement statt XmlArrayItem.

Natürlich haben unterschiedliche Dienste unterschiedliche Anforderungen. Die Fiddler-Anwendung (http://fiddler2.com/) kann wirklich helfen, die Serialisierung zu überprüfen, um sicherzustellen, dass Sie es richtig machen. Fiddler hat mir wirklich sehr geholfen.Hier ein paar zusätzliche Informationen, die mir auch geholfen haben: http://msdn.microsoft.com/en-us/library/2baksw0z.aspx

Verwandte Themen