2010-10-01 8 views
12

Il mio team ha il compito di ottenere diverse applicazioni client .NET sviluppate internamente per connettersi ad alcuni nuovi servizi Web Java. Il servizio Web Java è un file WSDL di terze parti fornito dal fornitore che il nostro team ha una limitata capacità di modifica/controllo ... il che significa che probabilmente abbiamo il potere di chiedere al nostro fornitore di apportare piccole modifiche al WSDL, ma probabilmente ci sarebbero maggiori cambiamenti essere irrealizzabile o difficile da richiedere.Problemi di serializzazione WCF con file WSDL creati da strumenti Java

Detto questo, stiamo tentando di utilizzare WCF/.NET 4.0 per generare i file di classe proxy .NET di cui abbiamo bisogno sul lato client. Il processo di generazione del file di classe del client proxy viene eseguito senza problemi.

Il problema si verifica quando si tenta di utilizzare il file di classe proxy in un'app client. Ho verificato tramite lo strumento Web Trace, Fiddler, che la richiesta di messaggio SOAP non riesce a essere inviata attraverso il cavo al server.

La specifica dei messaggi di eccezione .NET ottengo quando si tenta di chiamare il metodo di servizio web in questione, si presenta così:

System.InvalidOperationException è stata gestita Messaggio = attributo XmlSerializer System.Xml.Serialization.XmlAttributeAttribute è non valido in baseLingua. Solo gli attributi XmlElement, XmlArray, XmlArrayItem, XmlAnyAttribute e XmlAnyElement sono supportati quando IsWrapped è true. Source = System.ServiceModel

Quando esamino il file generato automaticamente .NET classe proxy, Reference.cs, ho notato che i messaggi di richiesta e risposta per il mio metodo di servizio Web simile a questa:

[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] 
[System.ServiceModel.MessageContractAttribute(WrapperName="QueryPBOT_MXWO_OS", WrapperNamespace="http://www.ibm.com/maximo", IsWrapped=true)] 
public partial class QueryPBOT_MXWO_OSRequest { 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=0)] 
    public ConsoleApplication7.wsMaximo.PBOT_MXWO_OSQueryType PBOT_MXWO_OSQuery; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=1)] 
    [System.Xml.Serialization.XmlAttributeAttribute()] 
    public string baseLanguage; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=2)] 
    [System.Xml.Serialization.XmlAttributeAttribute()] 
    public string transLanguage; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=3)] 
    [System.Xml.Serialization.XmlAttributeAttribute()] 
    public string messageID; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=4)] 
    [System.Xml.Serialization.XmlAttributeAttribute()] 
    public string maximoVersion; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=5)] 
    [System.Xml.Serialization.XmlAttributeAttribute()] 
    [System.ComponentModel.DefaultValueAttribute(false)] 
    public bool uniqueResult; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=6)] 
    [System.Xml.Serialization.XmlAttributeAttribute(DataType="positiveInteger")] 
    public string maxItems; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=7)] 
    [System.Xml.Serialization.XmlAttributeAttribute(DataType="integer")] 
    [System.ComponentModel.DefaultValueAttribute("0")] 
    public string rsStart; 

    public QueryPBOT_MXWO_OSRequest() { 
    } 

    public QueryPBOT_MXWO_OSRequest(ConsoleApplication7.wsMaximo.PBOT_MXWO_OSQueryType PBOT_MXWO_OSQuery, string baseLanguage, string transLanguage, string messageID, string maximoVersion, bool uniqueResult, string maxItems, string rsStart) { 
     this.PBOT_MXWO_OSQuery = PBOT_MXWO_OSQuery; 
     this.baseLanguage = baseLanguage; 
     this.transLanguage = transLanguage; 
     this.messageID = messageID; 
     this.maximoVersion = maximoVersion; 
     this.uniqueResult = uniqueResult; 
     this.maxItems = maxItems; 
     this.rsStart = rsStart; 
    } 
} 

So che le persone che leggono questo post vorranno vedere il file WSDL che stiamo tentando di consumare, ma è abbastanza grande, e sono preoccupato che la sua dimensione potrebbe rendere difficile l'individuazione dell'errore.

Spero che il file proxy client generato automaticamente e l'eccezione .NET consentiranno a qualcuno di riconoscere questo problema di serializzazione WCF.

Abbiamo confermato dal nostro fornitore Java che lo stile di WSDL che generano è doc-letterale. Dopo aver fatto qualche ricerca su internet, sembra che WCF, di default. traduce i file WSDL con doc-literal wrapped e questo potrebbe spiegare, almeno in parte, perché stiamo riscontrando questo problema di serializzazione WCF con il file WSDL.

ho scoperto, attraverso tentativi ed errori, che il seguente decoratore attributo nel file di classe proxy è il colpevole dietro il problema di serializzazione:

[System.Xml.Serialization.XmlAttributeAttribute()]

Se commento tutte le istanze di questo attributo nel file di classe proxy e rieseguo la mia app client, il messaggio SOAP viene inviato correttamente attraverso il filo e viene restituita una risposta di servizio Web valida dal server.

Questa soluzione è meglio di niente, ma preferirei una soluzione che non richieda a me stesso o a nessuno del mio team di modificare costantemente questi file di classi proxy autogenerati .NET.

Vorrei sapere se c'è qualcosa che posso fare, tramite i vari strumenti WCF o modificando il file WSDL, che impedisce che [System.Xml.Serialization.XmlAttributeAttribute()] venga applicato alla mia richiesta e le proprietà dell'oggetto risposta?

O almeno una descrizione di alto livello di PERCHÉ vediamo questo comportamento di serializzazione in .NET con il file WSDL Java?

grazie in anticipo, John

+0

L'XmlAttributeAttribute viene aggiunto da voi o generato da WCF? –

+0

XMLAttributeAttribute viene generato dagli strumenti WCF e non capisco perché. Se è presente un qualche tipo di switch nello strumento per impedire che venga creato, o qualcosa che possiamo cambiare nel file WSDL di origine, possiamo evitare di modificare il file della classe proxy per farlo funzionare. –

+0

Avete una richiesta di sapone di lavoro campione dal vostro fornitore Java? –

risposta

3

basato sul codice generato sembra che il vostro servizio Java si aspetta richiedere come:

<s:Envelope xmlns:s="..."> 
    ... 
    <s:Body> 
    <QueryPBOT_MXWO_OS xmlns="http://www.ibm.com/maximo" baseLanguage="..." transLanguage="..." ...> 
     <PBOT_MXWO_OSQuery> 
     ... 
     </PBOT_MXWO_OSQuery> 
    </QueryPBOT_MXWO_OS> 
    </s:Body> 
</s:Envelope> 

Il problema è che WCF riconosciuto QueryPBOT_MXWO_OS come elemento wrapper per richiesta. Non sono sicuro del motivo per cui genera un'eccezione, ma probabilmente c'è qualche restrizione che l'elemento wrapper non possa avere attributi. Sono sospettoso che questa sia solo la gestione degli errori globali condivisa con la versione che utilizza IsWrapped = false dove l'utilizzo degli attributi è un errore.

Si può tentare di modificare il proxy in questo modo:

[System.Diagnostics.DebuggerStepThroughAttribute()]   
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]   
[System.ServiceModel.MessageContractAttribute(IsWrapped=false)]   
public partial class QueryPBOT_MXWO_OSRequest 
{ 
    [MessageBodyMemberAttribute(Name="QueryPBOT_MXWO_OS", Namespace="http://www.ibm.com/maximo")] 
    public QueryPBOT_MXWO_OS QueryPBOT_MXWO_OS { get; set; } 
} 

[XmlRoot(ElementName="QueryPBOT_MXWO_OS", Namespace="http://www.ibm.com/maximo")] 
public class QueryPBOT_MXWO_OS 
{ 
    [XmlElement(Namespace="http://www.ibm.com/maximo")]  
    public ConsoleApplication7.wsMaximo.PBOT_MXWO_OSQueryType PBOT_MXWO_OSQuery;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]   
    public string baseLanguage;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]   
    public string transLanguage;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]  
    public string messageID;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]  
    public string maximoVersion;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]  
    [System.ComponentModel.DefaultValueAttribute(false)]   
    public bool uniqueResult;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]  
    public string maxItems;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]   
    [System.ComponentModel.DefaultValueAttribute("0")]   
    public string rsStart; 
}  
+0

Laislav, grazie per il tuo commento, ma quello che cerco davvero è una soluzione in cui non devo assolutamente toccare il file di classe del proxy per far funzionare il servizio web. Se commento tutte le istanze di [XmlAttribute()] dal file di classe proxy, il servizio Web funzionerà. –

+1

Ma in questo caso tutti questi parametri vengono trasportati come elementi. Quindi hai bisogno di quei parametri? Se non è sufficiente rimuoverli da WSDL e rigenerare il proxy. –

9

Usa svcutil.exe utilità con l'opzione/avvolto opzione su per generare classi proxy.

Questo creerà classi leggermente diverse da quelle create con Visual Studio in un modo descritto da Ladislav Mrnka qui. I proxy risultanti dovrebbero essere liberi dal problema XmlAttribute quando si utilizza sul lato client.

Esempio:

svcutil /t:code wsdl.xml /out:wsdl.cs /serializer:XmlSerializer /wrapped 
2

Ecco come fare soluzione di Mikhail G entro IDE:

  • Aprire Reference.svcmap sotto Servizio Referenze
  • Aggiungi <Wrapped>true</Wrapped> sotto <ClientOptions> e risparmiare
  • destro Fai clic su Reference.svcmap e premi "Esegui strumento personalizzato"

Visual Studio, dove la magia accade :)

Nota: Provato con VS 2015. Le versioni precedenti può avere stessa opzione con un nome diverso da quello "Esegui strumento personalizzato"

+1

Fantastico, questo ha risolto il mio problema! –

1

Come Seguendo la risposta di stratovarius, in VS 2017 la cartella Riferimenti servizio viene sostituita da Servizi connessi, quindi è necessario:

  1. Aprire la cartella {project}/Connected Services in Wi ndows Explorer
  2. trovare e modificare il Reference.svcmap con un editor di testo
  3. Aggiungere <Wrapped>true</Wrapped> alla sezione <ClientOptions>
  4. Salvare il file
  5. In VS, fare clic destro sul riferimento al servizio in servizi connessi e selezionare "Aggiornamento Servizio di riferimento "

Questo ha eliminato l'eccezione dalla mia chiamata di servizio.

Problemi correlati