2013-10-21 15 views
7

ho le seguenti ServiceContract e DataContract classi:Lista WCF errore <string > di serializzazione/deserializzazione

[ServiceContract] 
public interface IWcfService 
{ 
    [OperationContract] 
    Response GetData(); 
} 

[DataContract] 
public class Response 
{ 
    [DataMember] 
    public Dictionary<string, object> Data { get; set; } 
} 

Quando il valore di dizionario Response.Data è di tipo int, string, doppia o altri tipi primitivi 'semplici' , WCF può serializzare correttamente l'oggetto. Ma quando il valore del dizionario Response.Data è di tipo List < string>, il cliente ha gettato seguente eccezione quando itreceived i dati e ha cercato di deserializzare esso:

Message=The formatter threw an exception while trying to deserialize the message: 
There was an error while trying to deserialize parameter http://tempuri.org/:GetDataResult. 
The InnerException message was 'Error in line 1 position 990. 
    Element 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:Value' contains data from a type 
    that maps to the name 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:ArrayOfstring'. 
    The deserializer has no knowledge of any type that maps to this name. 
    Consider using a DataContractResolver or add the type corresponding to 'ArrayOfstring' 
    to the list of known types - for example, by using the KnownTypeAttribute attribute or 
    by adding it to the list of known types passed to DataContractSerializer.'. 

Ho anche provato ad aggiungere l'attributo al KnownType ServiceContract e DataContract come segue:

[ServiceContract] 
[ServiceKnownType(typeof(List<string>))] 
[ServiceKnownType(typeof(Dictionary<string, string>))] 
[ServiceKnownType(typeof(Dictionary<string, List<string>>))] 
public interface IWcfService 
{ 
    [OperationContract] 
    [ServiceKnownType(typeof(List<string>))] 
    [ServiceKnownType(typeof(Dictionary<string, string>))] 
    [ServiceKnownType(typeof(Dictionary<string, List<string>>))] 
    Response GetData(); 
} 

[DataContract] 
[ServiceKnownType(typeof(List<string>))] 
[ServiceKnownType(typeof(Dictionary<string, string>))] 
[ServiceKnownType(typeof(Dictionary<string, List<string>>))] 
[KnownType(typeof(List<string>))] 
[KnownType(typeof(Dictionary<string, string>))] 
[KnownType(typeof(Dictionary<string, List<string>>))] 
public class Response 
{ 
    [DataMember] 
    public Dictionary<string, object> Data { get; set; } 
} 

Ma niente di tutto questo ha aiutato. Qualcuno ha qualche idea su questo?

Aggiornato

I Dati sarà simile:

Data = new new DIctionary<string, object> 
     { 
      {"_id", 12344}, 
      {"names", new List<string>{ "John", "Peter", "Jack"}}, 
      {"time", DateTime.Now} 
     } 

Il motivo per cui abbiamo usato Dizionario < string, object>: server deve inviare al cliente un dizionario di 'dinamica' dati, che possono essere int, List, DataTime, ecc. Aiuterà a risolvere questo problema usando Dictionary, ma anche a perdere le informazioni sul tipo originale. Ad esempio, il client ha bisogno di Elenco e crea un certo legame con i dati per visualizzare la raccolta, quindi List.ToString() non sarà utile in questo caso.

+2

Presumibilmente uno dei valori nel dizionario è 'string []' o 'Lista '? Devo dire: l'uso di 'object' *** in qualsiasi punto *** in un contratto di dati dovrebbe immediatamente attivare campane d'allarme. 'object' * non è un contratto * - è l'assenza totale * di un contratto. Però! Hai provato a includere '[KnownType (typeof (string []))]// [ServiceKnownType (typeof (string []))]' (nota: aggiungere attributi casuali non è il modo migliore per "aggiustare" qualcosa) –

+0

When i valori nel dizionario sono Lista , causa il problema. Ho anche provato a usare [KnownType (typeof (string []))]/[ServiceKnownType (typeof (string []))], ma non ha aiutato – wd113

+0

Stai usando Aggiungi riferimento di servizio per creare un client che chiama il servizio? –

risposta

1

Grazie per gli input di tutti. Sono riuscito a sovogliere il problema configurando WCF per utilizzare NetDataContractSerializer come serializzatore (quello predefinito è DataContractSerializer). NetDataContractSerializer includerà più informazioni di tipo CLR durante la serializzazione, sebbene abbia un impatto sulle prestazioni (circa il doppio del tempo di serializzazione).

+0

Grazie per il suggerimento! L'ho usato per risolvere il mio problema di vecchia data su come inviare un'eccezione dal client al server per la registrazione. Ecco come ho [fatto] (http://stackoverflow.com/a/28737527/722393). Grazie ancora. – InteXX

1

Tenete a mente che il vostro contratto di dati viene serializzato in stringhe attraverso il cavo, in modo che qualsiasi oggetto che si passa over deve essere serializzabile (che non è object).

Il problema è che si utilizzano modelli orientati agli oggetti in un contesto orientato al servizio - in attesa che tutto ciò che si passa nel valore del dizionario sia polimorfo su object. Ho risposto a una domanda che aveva simili "odori" qui: https://stackoverflow.com/a/19445875/2382536.

Il problema è attribuibile al fatto che WCF è così bravo a sottrarre il canale sottostante del servizio, si è tentati di dimenticare che si sta lavorando in un contesto "Servizio orientato" (KnownTypes è un mod l'illusione di OO sul filo). Un contratto di dati fa parte dell'API "pubblica" al tuo servizio e, come tale, deve essere una chiara rappresentazione esplicita dei dati esposti dal servizio. Avere una struttura dati che restituisce dati "dinamici" viola questa importante regola.

Il client deve sapere quali dati vengono restituiti, quindi se si desidera implementare una risposta "dinamica", è necessario implementare (diciamo) diversi metodi/endpoint/servizi per le variazioni nella risposta. All'interno del vostro servizio non vi è alcun motivo per cui non sia possibile utilizzare il polimorfismo per semplificare il codice, ma questo non dovrebbe trapelare nei contratti di servizio pubblico/dati.

Problemi correlati