2009-02-18 13 views
6

Chcę wiedzieć, jak skonfigurować znane typy w WCF. Na przykład mam klasę Person i klasę Employee. Klasa Employee to sublas klasy Person. Obie klasy są oznaczone atrybutem [DataContract].WCF: Konfigurowanie znanych typów

Nie chcę zakodować na sztywno znanego typu klasy, np. Wstawiając [ServiceKnownType(typeof(Employee))] w klasie Person, aby WCF wiedział, że Pracownik jest podklasą Osoby.

Teraz dodałem do app.config następującej konfiguracji XML gospodarza:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.runtime.serialization> 
    <dataContractSerializer> 
     <declaredTypes> 
     <add type="Person, WCFWithNoLibrary, Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"> 
      <knownType type="Employee, WCFWithNoLibrary, Version=1.0.0.0,Culture=neutral, PublicKeyToken=null" /> 
     </add> 
     </declaredTypes> 
    </dataContractSerializer> 
    </system.runtime.serialization> 
    <system.serviceModel> 
    ....... 
    </system.serviceModel> 
</configuration> 

Skompilowałem go uruchomić hosta, dodane odniesienie usług na kliencie i dodał jakiś kod i uruchomić klienta. Ale wystąpił błąd:

Program formatujący zwrócił wyjątek podczas próby deserializacji komunikat: Wystąpił błąd podczas próby deserializowania parametru http://www.herbertsabanal.net:person. Komunikat InnerException był „błąd w linii 1 pozycji 247. Element 'http://www.herbertsabanal.net:person' zawiera dane zamówienia danych 'http://www.herbertsabanal.net/Data:Employee' . Deserializator nie ma wiedzy o każdym typie mapującym do tego kontraktu na . Dodaj typ odpowiadający 'pracownika do listy znanych typów - na przykład przez Używanie KnownTypeAttribute przypisują lub dodając go do listy znanych typów przekazywanych DataContractSerializer. ". Aby uzyskać więcej informacji, zobacz temat InnerException.

Poniżej znajdują się kontrakty danych:

[DataContract(Namespace="http://www.herbertsabanal.net/Data", Name="Person")] 
    class Person 
    { 
     string _name; 
     int _age; 

     [DataMember(Name="Name", Order=0)] 
     public string Name 
     { 
      get { return _name; } 
      set { _name = value; } 
     } 

     [DataMember(Name="Age", Order=1)] 
     public int Age 
     { 
      get { return _age; } 
      set { _age = value; } 
     } 
    } 


[DataContract(Namespace="http://www.herbertsabanal.net/Data", Name="Employee")] 
    class Employee : Person 
    { 
     string _id; 

     [DataMember] 
     public string ID 
     { 
      get { return _id; } 
      set { _id = value; } 
     } 
    } 

Btw, nie korzystają z bibliotek klas (biblioteki klas WCF lub bibliotek klas non-WCF) na moje usługi. Po prostu zakodowałem to w głównym projekcie.

Domyślam się, że w pliku konfiguracyjnym musi być jakiś problem (proszę zobaczyć plik konfiguracyjny powyżej). Albo musi mi brakować czegoś. Każda pomoc byłaby bardzo doceniana.

+0

Podejrzewam, że konfiguracja działa tylko w przypadku korzystania z biblioteki innej firmy, odwołując się do tej usługi. Spróbuję i powrócę do tego pytania, jeśli znajdę jakieś odpowiedzi. – jerbersoft

Odpowiedz

8

Chyba znalazłem odpowiedź teraz.

Plik konfiguracyjny napisałem powyżej wygląda następująco:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.runtime.serialization> 
    <dataContractSerializer> 
     <declaredTypes> 
     <add type="Person, WCFWithNoLibrary, Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"> 
      <knownType type="Employee, WCFWithNoLibrary, Version=1.0.0.0,Culture=neutral, PublicKeyToken=null" /> 
     </add> 
     </declaredTypes> 
    </dataContractSerializer> 
    </system.runtime.serialization> 
    <system.serviceModel> 
    ....... 
    </system.serviceModel> 
</configuration> 

Co Właśnie dodałem była przestrzeń nazw Osoba klasy i Pracownik klasa. Nie ma potrzeby dłuższej wersji Wersji i Kultury .... Prawidłowa konfiguracja powinna być:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.runtime.serialization> 
    <dataContractSerializer> 
     <declaredTypes> 
     <add type="WCFWithNoLibrary.Person, WCFWithNoLibrary"> 
      <knownType type="WCFWithNoLibrary.Employee, WCFWithNoLibrary" /> 
     </add> 
     </declaredTypes> 
    </dataContractSerializer> 
    </system.runtime.serialization> 
    <system.serviceModel> 
    ....... 
    </system.serviceModel> 
</configuration> 

Teraz jest krótsza i ma więcej sensu. Ale jeśli używane są biblioteki osób trzecich, wymagane będzie dodanie wersji, kultury, publickeytokens.

+2

Awans. Czy musisz zrobić coś po stronie klienta .config? – granadaCoder

+1

Powtórz konfigurację na kliencie, aby mógł otrzymać nowy typ. –

5

Znam ten odpowiedział już dawno temu, ale kolejną (być może bardziej oczywiste dla przyszłych programistów) rozwiązanie:

[KnownType(typeof(SubClass))] 
public class BaseClass 

Scotta

+4

nie zawsze jest to możliwe, jeśli podtyp jest w innym projekcie –

0

mam to długi komunikat o błędzie także w innej sprawie. Użyłem KnownTypeAttribute i udało mi się wdrożyć aplikację, która używa do produkcji WCF.RIA. W drugim wydaniu dodałem nowy podtyp i dodałem niezbędne odpowiednie KnownTypeAttribute (kompilator nie zaakceptował go bez tego atrybutu - super). To, co kompilator zaakceptował i co działało na mojej maszynie, nie działało jednak w produkcji. Tylko w produkcji dostałem błąd wspomniany powyżej. Porównując wszystkie zastosowania istniejących podtypów, a nowy ujawnił, zapomniałem, że WCF.RIA wymaga podania nazwy podtypu w nazwie metody, np. GetMySubTypes. Więc jeśli pojawi się ten błąd po dodaniu atrybutów, sprawdź, czy jest to spowodowane konwencjami WCF.RIA.

Powiązane problemy