2010-01-29 6 views
6

Ho cercato di utilizzare un client SilverLight per chiamare un servizio WCF di ASP.Net che restituirebbe un valore Dictionary<string, object>. Questo ha funzionato correttamente quando i valori nel dizionario erano semplici tipi come int, string o Guid.Servizio WCF che restituisce un array di dizionario <stringa, oggetto>

Tuttavia, ora ho uno scenario in cui ho bisogno di uno dei valori per essere un array di Dictionary<string, object>! Compilano tutti bene e la firma del servizio non è cambiata, ma la chiamata di servizio non riesce.

Qualche idea su come risolverlo? Ho provato ad annotare la mia classe di servizio e i metodi con gli attributi KnownType e ServiceKnownType ma non ha funzionato.

Ecco un pezzo di codice:

[ServiceContract(Namespace = "")] 
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] 
public class Service1 
{ 
    [OperationContract] 
    [ServiceKnownType(typeof(Dictionary<string, object>))] 
    public Dictionary<string, object> GetObject() 
    { 
     return new Dictionary<string, object>() 
      { 
       { "pty1", 1 }, 
       { "pty2", Guid.NewGuid() }, 
       { "pty3", "blah" }, 
       { "pty4", new Dictionary<string, object>[] 
           { 
            new Dictionary<string, object>() 
             { 
              { "pty1", 4 }, 
              { "pty2", Guid.NewGuid() }, 
              { "pty3", "blah" }, 
             } 
            , 
            new Dictionary<string, object>() 
             { 
              { "pty1", 4 }, 
              { "pty2", Guid.NewGuid() }, 
              { "pty3", "blahblah" }, 
             } 
           } 
      } 
     }; 
    } 
} 

Grazie per le vostre risposte. Ho attivato il tracciamento WCF e, come sospetto, c'è un problema durante la serializzazione. Il problema non è la serializzazione di Dictionary<string, object> ma quella di di Dictionary<string, object>.

Qui l'eccezione registrata dal servizio WCF.

Si è verificato un errore durante il tentativo di serializzare il parametro: GetObjectResult. Il messaggio InnerException era 'Type' System.Collections.Generic.Dictionary`2 [[System.String, mscorlib, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089], [System.Object, mscorlib, Version = 2.0. 0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]] [] 'con nome contratto dati' ArrayOfArrayOfKeyValueOfstringanyType: http://schemas.microsoft.com/2003/10/Serialization/Arrays 'non è previsto. Aggiungi qualsiasi tipo non noto staticamente all'elenco dei tipi noti, ad esempio utilizzando l'attributo KnownTypeAttribute o aggiungendoli all'elenco dei tipi noti passati a DataContractSerializer. '. Si prega di consultare InnerException per maggiori dettagli.

Ho anche provato a definire una nuova classe DataContract con un singolo membro di dati, ma conduce allo stesso errore.

Ecco il codice per questo, seguito dall'eccezione registrata dalla registrazione WCF.

[DataContract] 
[KnownType(typeof(ObjectHolder))] 
public class ObjectHolder 
{ 
    [DataMember] 
    public object Object { get; private set; } 

    public ObjectHolder(object obj) 
    { 
     this.Object = obj; 
    } 
} 

Si è verificato un errore durante il tentativo di serializzare parametro: GetObjectResult. Il messaggio InnerException era 'Type' System.Collections.Generic.Dictionary`2 [[System.String, mscorlib, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089], [SilverlightApplication7.Web.ObjectHolder, SilverlightApplication7.Web, Versione = 1.0.0.0, Culture = neutro, PublicKeyToken = null]] [] 'con nome contratto dati' ArrayOfArrayOfKeyValueOfstringObjectHolderWAwxSTlb: http://schemas.microsoft.com/2003/10/Serialization/Arrays 'non è previsto. Aggiungi qualsiasi tipo non noto staticamente all'elenco dei tipi noti, ad esempio utilizzando l'attributo KnownTypeAttribute o aggiungendoli all'elenco dei tipi noti passati a DataContractSerializer. '. Si prega di consultare InnerException per maggiori dettagli.

Ancora una volta ho giocato con ServiceKnownType per ObjectHolder, ObjectHolder[] e anche ObjectHolder[][] poiché l'eccezione menziona un "ArrayOfArrayOfKeyValueOfstringObjectHolder".

Ancora nessuna soluzione.

+0

Che errore ricevi? –

+0

La mia ipotesi sarebbe che la WCF potesse avere problemi nel serializzare l'oggetto. Potresti provare a creare i tuoi dizionari se ciò è fattibile. – sipwiz

+0

Sono d'accordo con sipwiz, avrete problemi a serializzare il dizionario. Dovresti fare in modo che il dizionario contenga un oggetto serializzabile (significa che devi cambiare il tuo dizionario per Dictionary srodriguez

risposta

0

Provare a definire una classe con una proprietà singola. Quella proprietà è un dizionario di stringa, oggetto.

Contrassegnare la classe con DataContract/DataMember. Quindi definisci la tua interfaccia usando quella classe.

8

Prima di tutto è necessario configure WCF tracing in file cofig app che può aiutare a capire cosa succede sotto la cappa delle comunicazioni di servizio. In questo caso è possibile ottenere facilmente tutti gli errori che si verificano durante il processo di comunicazione.

Ora proviamo a risolvere il problema. Sono quasi sicuro che il problema riguardi tipi noti. Nel mondo orientato ai servizi è necessario definire manualmente tutti i tipi concreti che possono partecipare al contratto di servizio, poiché DataContractSerializer non fornisce tali informazioni in oggetti serializzati.

In questo caso significa, che si dovrebbe fare seguente:

[ServiceKnownType(typeof(string))] 
[ServiceKnownType(typeof(Guid))] 
[ServiceKnownType(typeof(int))] // but I think DataContractSerializer can deal himself with primitives 
[ServiceKnownType(typeof(YourClass))] //UserDefined types you should add manually 
public Dictionary<string, object> GetObject() 

Anche io raccomanda di non utilizzare oggetto nel contratto di servizio, perché l'errore molto incline. Si consideri, che poi voi o uno dei vostri colleghi modifica una riga di codice:

new Dictionary<string, object>() 
{ 
{ "pty1", 4 }, 
{ "pty2", Guid.NewGuid() }, 
{ "pty3", new SomeClass() }, //OOPS!!! 
} 

In questo caso, quando il servizio tenta di restituire questo dizionario si verifica il fallimento runtime perché DataContractSerializer non si aspetta SomeClass nel presente contratto.

Un modo per risolvere questo problema è quello di creare tipo distinto:

[DataContract] 
[KnownType(typeof(Guid))] 
[KnownType(typeof(SomeClass1))] 
[KnownType(typeof(SomeClass2))] 
public class MyType 
{ 
    private MyType(object obj) { 
    Object = obj; 
    } 

    public static MyType FromSomeClass1(SomeClass1 c1) { 
    return new MyType(c1); 
    } 

    public static MyType FromSomeClass2(SomeClass2 c2) { 
    return new MyType(c2); 
    } 

    public static MyType FromGuid(Guid guid) { 
    return new MyType(guid); 
    } 

    [DataMember] 
    public object Object { get; private set; } 
} 

In questo caso, se si desidera aggiungere qualche nuovo tipo, si dovrebbe aggiungere metodo factory e KnownTypeAttribute (questo approccio più prolisso, ma meno incline a errori).

Tuttavia, se il client e il servizio sono scritti su WCF, è possibile sacrificare i principi orientati ai servizi principali e utilizzare NetDataContractSerializer invece DataContractSerializer. NetDataContractSerializer è progettato per integrare DataContractSerializer. È possibile serializzare un tipo utilizzando NetDataContractSerializer e deserializzare con DataContractSerializer. Ma NetDataContractSerializer include informazioni sul tipo CLR nell'XML serializzato, mentre il DataContractSerializer no. Pertanto, NetDataContractSerializer può essere utilizzato in serializzazione e deserializzazione con qualsiasi tipo di CLR senza alcuna roba di KnownTypes.

+0

Questa è la migliore risposta, si potrebbe migliorare sottolineando che non è il dizionario che è il tipo sconosciuto, ma i tipi di oggetti contenuti all'interno del dizionario.Questo è il motivo per aggiungere [ServiceKnownType (typeof (Dictionary ))] non aiuta, mentre aggiunge [ServiceKnownType (typeof (types_which_the_object_might_be)] fa. –

0

Tuttavia, ora ho uno scenario in cui ho bisogno di uno dei valori per essere una matrice di dizionario!

Il problema è che WCF non sa come serializzatore/deserializzare un array di oggetti che non è contrassegnata con attributo DataMember e/o non viene aggiunta al ServiceKnownType s.

Per esempio, se c'è qualche metodo di servizio, che prende un oggetto arbitrario come parametro

public interface IService 
    function DoSomething(Parameter as Object) as integer 
end interface 

e si desidera passare, dire un array di interi Integer(), è necessario aggiungere in modo esplicito questo array di interi digitare per servire tipi noti.

<ServiceKnownType(GetType(Integer()))> 
public interface IService 
    function DoSomething(Parameter as Object) as integer 
end interface 

Poi metodo di servizio può essere chiamato

dim Service as IService 
dim Argument as Integer() 
Service.DoSomething(Argument) 

Delle idee come risolvere il problema?

Prova ad aggiungere l'attributo <ServiceKnownType(GetType(Dictionary(Of String, Object)()))>.

Problemi correlati