2010-08-06 7 views
5

Parece que hay un error conocido en wsdl.exe, la herramienta que Visual Studio usa para generar proxies de servicios web. Con ciertos esquemas XSD, la herramienta generará clases que no se pueden deserializar del XML.¿Cómo puedo arreglar el proxy de referencia web que generó Visual Studio para manejar arreglos irregulares?

Por lo que a mí respecta, eso es inaceptable, pero no sé cómo solucionarlo.

Describiré mi caso en detalle, espero que alguien pueda ayudarme con eso.

esquema

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

respuesta XML del servicio web

Una respuesta típica de acuerdo con este esquema es el siguiente:

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

Utilizando los tipos de código de

que hubiera esperado a ser capaz de utilizar los tipos CLR así:

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

En cambio, el tipo generado por el resultado tiene el siguiente aspecto:

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

Lo cual no tiene ni siquiera ¡permita que se genere el ensamble de serialización!

No se puede convertir tipo Portfolio.WebService.multiValuedAttribute a Portfolio.WebService.multiValuedAttribute []

Arreglándolo

1 - Cambiar el tipo de la propiedad y campo

Ahora una de las soluciones que encontré en línea es simplemente eliminar un par de corchetes del tipo de la generación rados propiedad:

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

Eso permite que el ensamblado de serialización que se construirá, y se ejecuta sin excepciones, excepto que no serializa los datos correctamente, 'salta' la lista de activos y deserializa los atributos del primer assets elemento. Entonces no es una solución, porque con esta corrección no puedo consumir los datos. Para más de 700 activos, da result.assets es igual a multiValuedAttribute[2] (los 2 elementos son los atributos de nombre y palabras clave del primer activo).

2 - Especificación del tipo de los elementos de XML-

La segunda cosa que probé es dar deserializador diferentes instrucciones:

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

Así que ahora estoy diciéndole que cada elemento de la la secuencia es del tipo multiValuedAttribute[].Eso está mal porque todavía está mirando elementos attributes, que son del tipo multiValuedAttribute (solo, no una matriz). Sin embargo, se ejecuta, pero ahora el result.assets es igual a multiValuedAttribute[2][0] y aún no puedo acceder a los datos.

¿Qué sigue?

No tengo ni idea, razón por la cual escribí esto. No puedo aceptar que .NET no pueda consumir este servicio web, porque tiene que hacerlo.

+0

¿Alguna vez llegar a una mejor solución para esto? Estoy frente a la cuestión exacta, pero tengo cientos de tipos que necesitaría la modificación de –

Respuesta

3

Creo que deberías definir una clase de activo separada que tendría la propiedad de tipo multiValuedAttribute []. Por lo tanto, sería algo como

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

public partial class listAssetsQueryResults { 
    private Asset[] assetsField; 

    public Asset[] assets { 

Luego hay que decorar tipo de activos, atributos de la propiedad & activos con alguna combinación de XmlElement/XmlArrayElement/XmlArrayItemElement atributos para conseguir que funcione.

No hace falta decir que, cada vez que necesite volver a generar su código proxy, debe volver a aplicar los cambios anteriores (quizás pueda hacer un script por lotes para eso como una acción de compilación).

0

Siempre puede cambiar el tipo para que el servicio web devuelva algo amigable para el procesador wsdl. Por ejemplo, según el ejemplo que proporcionó, debería poder convertirlo fácilmente en una matriz de KeyValuePair<string, string> o algo así antes de devolverlo desde el servicio web.

Probablemente esta sea una mejor API que exponer matrices dentadas.

No puedo aceptar que .NET no es capaz de consumir este servicio web

Bueno, como mi amigo Madre Teresa dice: "La vida es una lucha, acepto". ;-)

+1

que no puedo cambiar el servicio web, que es parte del software de servidor que compramos. Que es también la razón por la que no puedo aceptar no ser capaz de consumir el servicio web, simplemente tengo que trabajar con lo que tengo. –

2

Este problema es muy típico cuando se consumen servicios web SOAP que fueron escritos en Java y luego consumidos por WCF, C#, .Net, etc. donde se utilizan matrices irregulares (matrices de matrices). La publicación de VinayC ayudó, pero aquí hay un código más explícito, por ejemplo, que puede ayudar a otros que se enfrentan a este problema.

Tenga en cuenta que estas clases están abreviadas. Su código WSDL generado seguramente se verá más complejo.

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

La clave aquí es crear una nueva clase 'activos' que es un enlace entre multiValuedAttribute y listAssetsQueryResults clases, y luego serializar el campo utilizando XmlElementAttribute. Una buena forma de hacerlo en sus propios proyectos es comenzar copiando y pegando la clase que sea análoga a la clase multiValuedAttribute (aunque esa implementación de clase no se muestra aquí). Luego, simplemente cambie el nombre de la clase multiValuedAttribute copiada como 'assets' y modifique la implementación para que funcione en su lugar como un enlace entre los dos. Elimine el extra [] en las instrucciones que contienen [] [] en la clase listAssetsQueryResults. Serialize usando XmlElement en lugar de XmlArrayItem.

Por supuesto, diferentes servicios tienen requisitos diferentes. La aplicación Fiddler (http://fiddler2.com/) realmente puede ayudar a inspeccionar la serialización para asegurarse de que la está haciendo bien. Fiddler realmente me ayudó mucho.Aquí es un poco de lectura adicional que me ayudó así: http://msdn.microsoft.com/en-us/library/2baksw0z.aspx

Cuestiones relacionadas