2009-06-10 10 views
8

Mam typ, nazwijmy go Data<TKey>. Mam również umowę o świadczenie usług WCF, która akceptuje typ (można nazwać to Wrapper) z właściwością typu Object (z powodów, do których nie będę się stosować, nie jest to opcjonalne).Jak określić typ WCF znany w konfiguracji, który jest ogólny?

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

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

Teraz wyślę dwie klasy IntData i LongData:

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

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

Oni obaj skonfigurowane w znanych typów pliku konfiguracyjnego. Konfiguracja przypomina coś podobnego:

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

W tym momencie wszystko działa poprawnie.

Ale mam zamiar dodać trzeci typ i nie lubię niepotrzebnych, pustych klas .NET IntData i LongData. Istnieją tylko dlatego, że ...

Nie wiem, jak określić typy ogólne w konfiguracji WCF!

Chcę zrobić coś takiego, ale nie znam dokładnej składni.

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

Jaka jest prawidłowa składnia tego?

(Zauważ też, że nie można umieścić [KnownType(...)] atrybuty Wrapper, gdyż nie jest w moim typie. Config wydaje się być jedynym sposobem.)

EDIT

@ odpowiedź Baretta pracował ładnie. Zauważ jednak, że początkowo otrzymałem ten błąd:

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.

Nie wspomniałem o tym w pierwotnym pytaniu, ale mój typ ma jawną nazwę kontraktu danych. Coś takiego:

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

Powyższy błąd wystąpił aż usunąłem wartość Name właściwości z atrybutem. Mam nadzieję, że pomaga to komuś innemu. Nie wiem, jaki format działa w tym scenariuszu. Te nie:

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

Ktoś wie jak to zrobić?

EDIT 2

Dzięki ponownie do @baretta który wskazał, że poprawna składnia jest w rzeczywistości:

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

Tak, wiem! :) Zmieniłem moją odpowiedź – baretta

Odpowiedz

18

typ rodzajowy jest chwilowe z ciągiem, jeśli ciąg następuje ten wzorzec: nazwę Class następnie przez "`" charakter, a następnie przez liczba parametrów typu (w tym przypadku 1), a następnie parametry typu zawarte w "[]" i użycie przecinka jako separatora parametrów typu.

<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: Mogę również dodać, że jeżeli informacja montaż musi być określona dla parametrów typu (althoug to nie jest sprawa dla rzeczy w mscorlib), następnie zagnieżdżone „[]” jest używany.

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

Edytuj: Można dostosować nazwy typów ogólnych w umowach danych, używając wzoru formatu ciągu.

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

Domyślnie Nazwa wygenerowany dla danych < Int32> Typ jest coś takiego jak „DataOfInt32HJ67AK7Y”, gdzie „HJ67AK7Y” jest hash wygenerowane z napisu „urn: domyślny”, lub nazw z listy klasa, jeśli masz. Ale "Dane {0}" nadałyby mu nazwę "DataInt32".

Więcej here. Zajrzyj na stronę "Dostosowywanie nazw umów dotyczących danych dla typów ogólnych".

+0

Dzięki Baretta. Ta zwięzła odpowiedź zadziałała doskonale, gdy tylko rozwiązałem problem z atrybutem name (zobacz moją edycję). –

+0

Dziękujemy za edytowanie. To jest świetna odpowiedź i gdybym mógł dwa razy głosować na nią, chciałbym :) –

+0

+1 za wskazówkę na temat dostosowywania nazw DataContract. Dzięki! – Dennis

5

Od 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’.

Powiązane problemy