2009-06-10 11 views
8

Ho un tipo, chiamiamolo Data<TKey>. Ho anche un contratto di servizio WCF che accetta un tipo (chiamiamolo Wrapper) con una proprietà di tipo Object (per motivi per cui non entrerò, questo non è facoltativo).Come specificare un tipo noto di WCF in configurazione generica?

[DataContract] 
public class Data<TKey> { ... } 

[DataContract] 
public class Wrapper 
{ 
    [DataMember] 
    public object DataItem { get; set; } 
} 

In questo momento mi sto inviando due classi IntData e LongData:

[DataContract] 
public class IntData : Data<int> { /*empty*/ } 

[DataContract] 
public class LongData : Data<long> { /*empty*/ } 

Sono entrambi configurati in tipi noti file di configurazione. La configurazione è simile a questa:

<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 correttamente.

Ma sto per aggiungere un terzo tipo e non mi piace avere le classi .NET non necessarie e vuote IntData e LongData. Esistono solo perché ...

Non so come specificare i tipi generici nella configurazione di WCF!

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 [KnownType(...)] attributi su Wrapper in quanto non è il mio tipo. Config sembra essere l'unico modo.)

EDIT

@ risposta di Baretta lavorato bene. Si noti, tuttavia, che inizialmente ho ricevuto questo errore:

Type 'MyAssembly.Data`1[System.Int64]' cannot be added to list of known types since another type 'MyAssembly.Data`1[System.Int32]' with the same data contract name ' http://www.mycompany.com/MyAssembly:Data ' is already present.

non ho menzionato nella domanda iniziale, ma il mio tipo ha un nome esplicito contratto di dati. Qualcosa di simile:

[DataContract(Name = "Data")] 
public class Data<TKey> { ... } 

è verificato l'errore sopra finché ho rimosso il valore Name struttura dall'attributo. Spero che aiuti anche qualcun altro. Non so quale formato funzioni in questo scenario. Non ce n'erano:

[DataContract(Name = "Data\`1")] 
[DataContract(Name = "Data{TKey}")] 

Qualcuno sa come fare?

EDIT 2

Grazie ancora a @baretta che ha sottolineato che la sintassi corretta è in realtà:

[DataContract(Name = "Data{0}")] 
+0

Sì, lo so! :) Ho modificato la mia risposta – baretta

risposta

18

Un tipo generico è istanziabile da una stringa, se la stringa segue questo schema: nome Classe seguito da un carattere "`", seguito dal numero di parametri del tipo (in questo caso è 1), seguito dai parametri del tipo racchiusi tra "[]" e usando la virgola come separatore del parametro 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> 

Edit: 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 "[]" è usato.

<knownType type="Data`1[[System.Int32, mscorlib]], MyAssembly"/> 

Edit: è possibile personalizzare i nomi dei tipi generici in contratti dati, utilizzando il modello in formato stringa.

[DataContract(Name = "Data{0}")] 
public class Data<TKey> 
{...} 

Per impostazione predefinita, il nome generato per il Data < Int32> tipo è qualcosa di simile "DataOfInt32HJ67AK7Y", dove "HJ67AK7Y" è un hash generato dalla stringa "urn: default", o lo spazio dei nomi della vostra classe, se ne hai. Ma "Data {0}" gli darebbe il nome "DataInt32".

Altro here. Dai un'occhiata alla parte "Personalizzazione dei nomi dei contratti dati per tipi generici" nella pagina.

+0

Grazie Baretta. Questa risposta sintetica ha funzionato perfettamente, una volta risolto il problema con l'attributo name (vedi la mia modifica). –

+0

Grazie per la tua modifica. Questa è un'ottima risposta e se potessi votare due volte, vorrei :) –

+0

+1 per il suggerimento sulla personalizzazione dei nomi DataContract. Grazie! – Dennis

5

Da here ...

Known types can also be defined in config as shown below.

<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> 

The above config specifies that the generic parameter for Circle is the same as the generic parameter for the declared type Shape. The config allows the definition of known type of arbitrary complexity. For example if it is needed to define Circle< Dictionary< string, T >> as the known type of Shape< T > (of course this is purely academic) it can be done as follows.

<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> 

Note the use config element “parameter” with the attributes ‘type’ and ‘index’.

Problemi correlati