Desidero che il mio servizio sia in grado di accettare e restituire tipi derivati da BaseType
senza sapere realmente quali saranno questi tipi. Ho quasi ottenuto una soluzione utilizzando un custom DataContractResolver
basato su SharedTypeResolver from this excellent blog post.Deserializzare i tipi derivati nel servizio WCF come tipi di base ma conservare le informazioni sul tipo
Il pezzo mancante del puzzle è che i tipi gestiti dal servizio potrebbero non essere condivisi e noti al servizio, ma desidero comunque accettarli ed essere a conoscenza di cosa il tipo avrebbe dovuto essere. Ho trovato il seguente esempio di un servizio che funge da stack. È possibile premere e inserire qualsiasi tipo derivato da BaseType
se si utilizza lo SharedTypeResolver
ei tipi sono condivisi tra client e server.
[DataContract]
public class BaseType
{
[DataMember]
public string SomeText { get; set; }
public override string ToString()
{
return this.GetType().Name + ": " + this.SomeText;
}
}
[DataContract]
public class DerivedType : BaseType
{
[DataMember]
public int SomeNumber { get; set; }
public override string ToString()
{
return base.ToString() + ", " + this.SomeNumber;
}
}
[ServiceContract]
public interface ITypeStack
{
[OperationContract]
void Push(BaseType item);
[OperationContract]
BaseType Pop();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class TypeStackService : ITypeStack
{
private Stack<BaseType> stack = new Stack<BaseType>();
public void Push(BaseType item)
{
this.stack.Push(item);
}
public BaseType Pop()
{
return this.stack.Pop();
}
}
Questo è ovviamente un esempio semplificato del problema riscontrato. Un cliente può tranquillamente spingere e pop BaseType
o DerivedType
perché sia il client che il server ne sono a conoscenza, ma se il client invia lo UnsharedType
che il servizio non conosce, ricevo un errore come ci si aspetterebbe.
Il formattatore ha generato un'eccezione durante il tentativo di deserializzare il messaggio : Si è verificato un errore durante il tentativo di deserializzare parametro http://tempuri.org/:item. Il messaggio InnerException era 'Errore nella riga 1 posizione 316. L'elemento' http://tempuri.org/:item 'contiene i dati da un tipo che corrisponde al nome' TestWcfClient, Versione = 1.0.0.0, Cultura = neutro, PublicKeyToken = null: TestWcfClient.UnsharedType ' . Il deserializzatore non è a conoscenza di alcun tipo associato a questo nome. Si consiglia di modificare l'implementazione del metodo ResolveName sul DataContractResolver per restituire un valore non nullo per il nome 'TestWcfClient.UnsharedType' e spazio dei nomi 'TestWcfClient, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null' '. . Vedere InnerException per ulteriori dettagli.
mio pensiero attuale è quello di aggiungere IExtensibleDataObject
a BaseType
per contenere i valori da un tipo non condivisa e fare un tipo non condivisa assomigliare BaseType
al servizio sulla deserializzazione quando un elemento viene spinto; il contrario dovrebbe accadere quando un oggetto è spuntato. Non sono sicuro di come farlo. I miei pensieri finora su possibili approcci:
- Ulteriori personalizzazioni a
DataContractResolver
che potrebbe comportare unTypeDelegator
- Utilizzando
IDataContractSurrogate
al posto di un tipo non condivisa - In qualche modo mantengono l'XML serializzato il servizio ricevuto quando un elemento viene spinto , quindi utilizzare questo in sede di replica quando un elemento viene spuntato
- Utilizzando un messaggio ispettore di manipolare i messaggi
Non ho idea se uno di questi funzionerà, cosa potrebbe essere coinvolto o quale sia la soluzione migliore. Fai?
Cambierete oggetti su un servizio, o avete solo bisogno di memorizzarli e inviarli ai clienti? – Enes
Basta archiviarli e inviarli indietro. Ho bisogno di conoscere il tipo di base in quanto ha alcune proprietà che il servizio utilizza per influenzare l'archiviazione, ma è di sola lettura per quanto riguarda il servizio. – batwad