2010-02-21 14 views
20

Ho un metodo di servizio WCF che si aspetta un oggetto e quindi recupera le sue proprietà utilizzando la reflection.Passare un'istanza di tipo anonimo su WCF

Sul lato client che creare un tipo di oggetto anonimo

var obj = new {FirstName="John", LastName="Doe"} 

e passarlo al metodo. Sto diventando un'eccezione:

Type '<>f__AnonymousType0`2[System.String,System.String]' cannot be serialized. 
Consider marking it with the DataContractAttribute attribute, and marking all 
of its members you want serialized with the DataMemberAttribute attribute. 
See the Microsoft .NET Framework documentation for other supported types. 

non riesco a segnare il tipo o dei suoi membri con attributi serializzazione perché non c'è davvero nessun tipo né beni dichiarati esplicitamente. C'è un modo per superare questo problema?

risposta

17

Non farlo.

È un tentativo di essere intelligente. Non farlo. Dichiara semplicemente il tipo di dati che ti serve e usalo. Se hai bisogno di un tipo di dati più generico, basta usare una mappatura dei valori-chiave di qualche tipo.

Ci vorranno 5 minuti per scrivere qualcosa che possa gestirlo per sempre. L'utilizzo di qualsiasi tecnica come questa ti costerà ore di debugging in qualche punto futuro lungo la strada.

+0

Sì, ho finito per passare un dizionario di chiavi-oggetti – Andrey

+0

Ho avuto lo stesso problema e passato mezza giornata prima ho capito che era una cattiva idea. Non è la mia ora migliore. Volevo solo sostenere kyoryu con l'aneddoto di ciò che ha profetizzato. – Four

1

Hai già la risposta. Non può essere fatto.

In effetti, non è possibile passare un'istanza di tipo anonimo da un metodo a un altro all'interno del proprio programma. Non puoi certo passare loro tra i programmi.

+0

in realtà, è possibile - è possibile definire un tipo di ritorno di "oggetto" e quindi solo restituire l'istanza di tipo anonimo. È un tipo anonimo, ma alla fine discende ancora da "oggetto". Non consigliato, né previsto - ma è possibile - almeno all'interno di .NET –

+0

@marc_s: questo potrebbe essere compilato ma praticamente inutile, poiché non verranno generati metadati per un tipo di ritorno di "System.Object". – Aaronaught

+0

@Aaronaught: non ho mai detto che fosse utile in qualsiasi modo, forma o forma - solo possibile :-) Non lo farei mai da solo, ma è tecnicamente possibile –

2

No, non c'è. Mentre esistono trucchi e tecniche per restituire oggetti di un tipo anonimo da un metodo, non è possibile inviarli su WCF.

WCF deve conoscere tutti i tipi di calcestruzzo che verranno inviati, poiché non si sta solo chiamando un metodo .NET. Invece, la chiamata al messaggio viene convertita in un messaggio serializzato e, pertanto, qualsiasi "cosa" passata su una chiamata WCF deve essere serializzabile, senza alcuna eccezione,.

19

Ilche si can't use an anonymous type over WCF sono errati.

Se si utilizza il valore predefinito DataContractSerializer per serializzare i tipi sul canale, quindi sì, le risposte sono corrette. Questo perché il DataContractSerializer supporta i seguenti scenari:

  1. Tipi serializzati mediante Serializable attribute
  2. Tipi serializzati mediante XML Serialization
  3. Tipi serializzati mediante DataContract attribute
  4. Plain-Old-C#-Object (POCO) Serialization

Rispettivamente, non riescono con tipi anonimi per i seguenti motivi:

  1. Non è possibile applicare attributi a tipi anonimi.
  2. La serializzazione XML richiede un costruttore senza parametri predefinito, che i tipi anonimi non hanno.
  3. come 1.
  4. Uguale 2.

Tuttavia, non si è costretti ad utilizzare il DataContractSerializer per serializzare i messaggi in WCF. È possibile creare un custom message formatter che è possibile utilizzare per eseguire personalmente la serializzazione.

Si ha un problema se i tipi che si inviano come risultato di richieste sono tipi anonimi. Quando si ottengono i risultati, avrà un nome definito all'interno di un namespace (non in un senso .NET, ma in un senso SOA) e si dovrà gestire la mappatura di quel tipo concreto di nuovo al tipo anonimo . Tuttavia, poiché non hai accesso al tipo anonimo effettivo o ai modi di costruirlo nel codice (almeno in modo dinamico), non hai altra scelta che passarlo come un oggetto se viene passato a te, che lo rende praticamente inutile, dal momento che tutti dovranno usare le cattive pratiche come la dinamica (non una cattiva pratica in sé, ma per aggirare queste limitazioni in questo caso, sì), o cast-by-example.

Quindi alla fine devo dire che, mentre è certamente possibile per serializzare i tipi anonimi e li inviano oltre il filo, il lavoro invovled di solito non è valsa la pena.

+2

+1 per una risposta tecnicamente corretta. -1 per aver menzionato una tecnica che è pura malvagità. Sono preoccupato che qualcuno leggerà questo e ignorerà l'avvertimento "cattive pratiche" - dimentica il refactoring, avresti bisogno di un esorcista. – Aaronaught

+5

Menzionare QUALSIASI tecnica dovrebbe essere considerata condivisione della conoscenza e non essere disprezzata. Inoltre, anche gli esorcisti devono conoscere i demoni. –

0

Come detto prima, gli oggetti devono essere deserializzabili e quindi sarà necessario definire la struttura in anticipo. Tuttavia, puoi usare l'ereditarietà per definirli e quindi ridurre il dolore. WCF fornisce l'attributo KnownType per consentire a un'operazione di servizio di ricevere un oggetto della classe base e deserializzarlo in un oggetto di una classe derivata. Quindi avrai solo una (o poche) operazioni di assistenza in grado di gestire tutti i tuoi scenari.

4

Si potrebbe serializzare l'oggetto in una stringa JSON e inviarlo tramite WCF, in questo modo:

//in WCF Server 
dynamic mysentclass = new { FirstName = "John", LastName = "Doe" }; 
string jsonstring = JsonConvert.SerializeObject(mysentclass, Newtonsoft.Json.Formatting.Indented); 
//send the string through WCF 

//in WCF client 
dynamic myreceivedclass = JsonConvert.DeserializeObject<dynamic>(jsonstring); 
MessageBox.Show(myreceivedclass.FirstName.ToString() + " " + myreceivedclass.LastName.ToString()); 

L'esempio utilizza Json.Net, che può essere ottenuto qui:

http://www.nuget.org/packages/Newtonsoft.Json/

Si potrebbe anche usare System.Web.Script.Serialization.JavaScriptSerializer (in System.Web.Extensions.dll), che non è potente come Json.Net, ma sarebbe sufficiente per oggetti semplici.

Problemi correlati