Come specificare un tipo noto WCF in config che è generico?
-
13-09-2019 - |
Domanda
Ho un tipo, chiamiamolo Data<TKey>
. Ho anche un contratto di servizio WCF che accetta un tipo (permette di chiamare Wrapper
), con una proprietà di tipo Object
(per ragioni che non andrà in, questo non è opzionale).
[DataContract]
public class Data<TKey> { ... }
[DataContract]
public class Wrapper
{
[DataMember]
public object DataItem { get; set; }
}
In questo momento sto inviando due classi IntData
e LongData
:
[DataContract]
public class IntData : Data<int> { /*empty*/ }
[DataContract]
public class LongData : Data<long> { /*empty*/ }
Sono entrambi configurati nei tipi noti file di configurazione. La configurazione assomiglia a qualcosa di simile:
<configuration>
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="Wrapper, TheirAssembly">
<knownType type="IntData, MyAssembly"/>
<knownType type="LongData, MyAssembly"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
</configuration>
A questo punto, tutto funziona bene.
Ma io sto per aggiungere un terzo tipo e non mi piace avere il superfluo, vuoto NET classi IntData
e LongData
. Esistono solo perché ...
non so come specificare tipi generici nella configurazione WCF!
Io voglio fare qualcosa di simile, ma non conosco la sintassi esatta.
<configuration>
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="Wrapper, TheirAssembly">
<!-- this syntax is wrong -->
<knownType type="Data{System.Int32}, MyAssembly"/>
<knownType type="Data{System.Int64}, MyAssembly"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
</configuration>
Qual è la sintassi corretta per questo?
(Si noti anche che non posso mettere gli attributi [KnownType(...)]
su Wrapper
dato che non è il mio tipo. Config sembra essere l'unico modo.)
Modifica
@ risposta di Baretta ha funzionato bene. Si noti, tuttavia, che inizialmente ho ricevuto questo errore:
Tipo 'MyAssembly.Data`1 [System.Int64]' non può essere aggiunto alla lista dei tipi conosciuti dal un altro tipo 'MyAssembly.Data`1 [System.Int32]' con lo stesso nome del contratto di dati ' http://www.mycompany.com/MyAssembly:Data ' è già presente.
Non ho menzionarlo nella domanda iniziale, ma il mio tipo ha un nome esplicito contratto di dati. Qualcosa di simile a questo:
[DataContract(Name = "Data")]
public class Data<TKey> { ... }
Si è verificato l'errore sopra finché ho rimosso il valore della proprietà Name
dall'attributo. Speranza che aiuta qualcun altro troppo. Non so quale formato funziona in questo scenario. Questi non ha fatto:
[DataContract(Name = "Data\`1")]
[DataContract(Name = "Data{TKey}")]
Qualcuno sa come fare questo?
Modifica 2
Grazie ancora a @baretta che ha sottolineato che la sintassi corretta è in realtà:
[DataContract(Name = "Data{0}")]
Soluzione
Un tipo generico è instanziabile da una stringa, se la stringa segue questo schema: Nome classe seguito da un carattere "`", seguito dal numero di parametri di tipo (in questo caso si tratta di 1), seguito dai parametri di tipo racchiusi all'interno di "[]", e usando la virgola come separatore di parametri di tipo .
<configuration>
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="Wrapper, TheirAssembly">
<!-- this syntax is all good -->
<knownType type="Data`1[System.Int32], MyAssembly"/>
<knownType type="Data`1[System.Int64], MyAssembly"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
</configuration>
Modifica:. Potrei anche aggiungere, che se le informazioni di montaggio deve essere specificato per i parametri di tipo (althoug non è il caso di roba in mscorlib), quindi nidificato "[]" viene utilizzato
<knownType type="Data`1[[System.Int32, mscorlib]], MyAssembly"/>
Modifica:. È possibile personalizzare i nomi dei tipi generici in contratti dati, utilizzando il modello formato di stringa
[DataContract(Name = "Data{0}")]
public class Data<TKey>
{...}
Per impostazione predefinita, il nome generato per il tipo di dati
qui . Date un'occhiata alla parte "Personalizzazione dei dati nomi contratto per i tipi generici" in basso nella pagina.
Altri suggerimenti
qui ...
Noto tipi possono essere definiti anche in config come illustrato di seguito.
<configuration>
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="MyCompany.Library.Shape`1,
MyAssembly, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
<knownType type="MyCompany.Library.Circle`1,
MyAssembly, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
<parameter index="0"/>
</knownType>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
</configuration>
È possibile che questo config specifica che il parametro generico per Circle è il uguale al parametro generico per la Forma tipo dichiarato. La configurazione permette la definizione di tipo noto di complessità arbitraria. Per esempio, se è necessario definire Circle
> come il tipo noto di Figura (ovviamente questo è puramente accademico) si può fare come segue.
<configuration>
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="MyCompany.Library.Shape`1,
MyAssembly, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
<knownType type="MyCompany.Library.Circle`1,
MyAssembly, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
<parameter type="System.Collections.Generic.Dictionary`2">
<parameter type="System.String"/>
<parameter index="0"/>
</parameter>
</knownType>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
</configuration>
Si noti l'uso elemento di configurazione “Parametro” con ‘tipo’ gli attributi e ‘index’.