Określanie transferu danych w kontraktach usług
Program Windows Communication Foundation (WCF) może być uważany za infrastrukturę obsługi komunikatów. Operacje usługi mogą odbierać komunikaty, przetwarzać je i wysyłać do nich komunikaty. Komunikaty są opisywane przy użyciu kontraktów operacji. Rozważmy na przykład następującą umowę.
[ServiceContract]
public interface IAirfareQuoteService
{
[OperationContract]
float GetAirfare(string fromCity, string toCity);
}
<ServiceContract()>
Public Interface IAirfareQuoteService
<OperationContract()>
Function GetAirfare(fromCity As String, toCity As String) As Double
End Interface
GetAirfare
W tym miejscu operacja akceptuje komunikat z informacjami o fromCity
i toCity
, a następnie zwraca komunikat zawierający liczbę.
W tym temacie opisano różne sposoby, w jaki kontrakt operacji może opisywać komunikaty.
Opisywanie komunikatów przy użyciu parametrów
Najprostszym sposobem opisania komunikatu jest użycie listy parametrów i wartości zwracanej. W poprzednim przykładzie fromCity
użyto parametrów i toCity
string do opisania komunikatu żądania, a wartość zwracana zmiennoprzecinkowa została użyta do opisania wiadomości odpowiedzi. Jeśli sama wartość zwracana nie jest wystarczająca do opisania wiadomości odpowiedzi, mogą być używane parametry out. Na przykład następująca operacja zawiera fromCity
i toCity
w komunikacie żądania oraz liczbę wraz z walutą w komunikacie odpowiedzi:
[OperationContract]
float GetAirfare(string fromCity, string toCity, out string currency);
<OperationContract()>
Function GetAirfare(fromCity As String, toCity As String) As Double
Ponadto możesz użyć parametrów referencyjnych, aby utworzyć część parametru zarówno żądania, jak i komunikatu odpowiedzi. Parametry muszą być typami, które można serializować (konwertowane na XML). Domyślnie program WCF używa składnika o nazwie DataContractSerializer klasa do wykonania tej konwersji. Większość typów pierwotnych (takich jak int
, string
, float
i DateTime
.) jest obsługiwana. Typy zdefiniowane przez użytkownika muszą zwykle mieć kontrakt danych. Aby uzyskać więcej informacji, zobacz Using Data Contracts (Korzystanie z kontraktów danych).
public interface IAirfareQuoteService
{
[OperationContract]
float GetAirfare(Itinerary itinerary, DateTime date);
[DataContract]
public class Itinerary
{
[DataMember]
public string fromCity;
[DataMember]
public string toCity;
}
}
Public Interface IAirfareQuoteService
<OperationContract()>
GetAirfare(itinerary as Itinerary, date as DateTime) as Double
<DataContract()>
Class Itinerary
<DataMember()>
Public fromCity As String
<DataMember()>
Public toCity As String
End Class
End Interface
Czasami element DataContractSerializer
nie jest odpowiedni do serializacji typów. Program WCF obsługuje alternatywny aparat serializacji , XmlSerializerktórego można również użyć do serializacji parametrów. Dzięki XmlSerializer temu można użyć większej kontroli nad wynikowym kodem XML przy użyciu atrybutów, takich jak XmlAttributeAttribute
. Aby przełączyć się na używanie XmlSerializer elementu dla określonej operacji lub całej usługi, zastosuj XmlSerializerFormatAttribute atrybut do operacji lub usługi. Na przykład:
[ServiceContract]
public interface IAirfareQuoteService
{
[OperationContract]
[XmlSerializerFormat]
float GetAirfare(Itinerary itinerary, DateTime date);
}
public class Itinerary
{
public string fromCity;
public string toCity;
[XmlAttribute]
public bool isFirstClass;
}
<ServiceContract()>
Public Interface IAirfareQuoteService
<OperationContract()>
<XmlSerializerFormat>
GetAirfare(itinerary as Itinerary, date as DateTime) as Double
End Interface
Class Itinerary
Public fromCity As String
Public toCity As String
<XmlSerializerFormat()>
Public isFirstClass As Boolean
End Class
Aby uzyskać więcej informacji, zobacz Using the XmlSerializer Class (Używanie klasy XmlSerializer). Pamiętaj, że ręczne przełączenie do elementu XmlSerializer , jak pokazano poniżej, nie jest zalecane, chyba że masz określone powody, aby to zrobić zgodnie z opisem w tym temacie.
Aby odizolować nazwy parametrów platformy .NET od nazw kontraktów, możesz użyć atrybutu MessageParameterAttribute i użyć Name
właściwości , aby ustawić nazwę kontraktu. Na przykład poniższy kontrakt operacji jest odpowiednikiem pierwszego przykładu w tym temacie.
[OperationContract]
public float GetAirfare(
[MessageParameter(Name="fromCity")] string originCity,
[MessageParameter(Name="toCity")] string destinationCity);
<OperationContract()>
Function GetAirfare(<MessageParameter(Name := "fromCity")> fromCity As String, <MessageParameter(Name := "toCity")> toCity As String) As Double
Opisywanie pustych komunikatów
Pusty komunikat żądania można opisać bez parametrów wejściowych ani referencyjnych. Na przykład w języku C#:
[OperationContract]
public int GetCurrentTemperature();
Na przykład w Visual Basic:
<OperationContract()>
Function GetCurrentTemperature() as Integer
Pusta wiadomość odpowiedzi może być opisana przez zwrócenie void
typu i brak parametrów wyjściowych ani referencyjnych. Na przykład w:
[OperationContract]
public void SetTemperature(int temperature);
<OperationContract()>
Sub SetTemperature(temperature As Integer)
Różni się to od operacji jednokierunkowej, takiej jak:
[OperationContract(IsOneWay=true)]
public void SetLightbulbStatus(bool isOn);
<OperationContract(IsOneWay:=True)>
Sub SetLightbulbStatus(isOne As Boolean)
Operacja SetTemperatureStatus
zwraca pusty komunikat. Zamiast tego może zwrócić błąd, jeśli wystąpił problem podczas przetwarzania komunikatu wejściowego. Operacja SetLightbulbStatus
nie zwraca nic. Nie ma możliwości przekazywania warunku błędu z tej operacji.
Opisywanie komunikatów przy użyciu kontraktów komunikatów
Możesz użyć pojedynczego typu do reprezentowania całego komunikatu. Chociaż w tym celu można użyć kontraktu danych, zalecanym sposobem jest użycie kontraktu komunikatów — pozwala to uniknąć niepotrzebnych poziomów zawijania w wynikowym pliku XML. Ponadto kontrakty komunikatów umożliwiają wykonywanie większej kontroli nad wynikowymi komunikatami. Na przykład możesz zdecydować, które informacje powinny znajdować się w treści wiadomości i które powinny znajdować się w nagłówkach wiadomości. W poniższym przykładzie pokazano użycie kontraktów komunikatów.
[ServiceContract]
public interface IAirfareQuoteService
{
[OperationContract]
GetAirfareResponse GetAirfare(GetAirfareRequest request);
}
[MessageContract]
public class GetAirfareRequest
{
[MessageHeader] public DateTime date;
[MessageBodyMember] public Itinerary itinerary;
}
[MessageContract]
public class GetAirfareResponse
{
[MessageBodyMember] public float airfare;
[MessageBodyMember] public string currency;
}
[DataContract]
public class Itinerary
{
[DataMember] public string fromCity;
[DataMember] public string toCity;
}
<ServiceContract()>
Public Interface IAirfareQuoteService
<OperationContract()>
Function GetAirfare(request As GetAirfareRequest) As GetAirfareResponse
End Interface
<MessageContract()>
Public Class GetAirfareRequest
<MessageHeader()>
Public Property date as DateTime
<MessageBodyMember()>
Public Property itinerary As Itinerary
End Class
<MessageContract()>
Public Class GetAirfareResponse
<MessageBodyMember()>
Public Property airfare As Double
<MessageBodyMember()> Public Property currency As String
End Class
<DataContract()>
Public Class Itinerary
<DataMember()> Public Property fromCity As String
<DataMember()> Public Property toCity As String
End Class
Aby uzyskać więcej informacji, zobacz Using Message Contracts (Używanie kontraktów komunikatów).
W poprzednim przykładzie DataContractSerializer klasa jest nadal używana domyślnie. Klasa XmlSerializer może być również używana z kontraktami komunikatów. Aby to zrobić, zastosuj XmlSerializerFormatAttribute atrybut do operacji lub kontraktu i użyj typów zgodnych z klasą XmlSerializer w nagłówkach komunikatów i składowych treści.
Opisywanie komunikatów przy użyciu Strumienie
Innym sposobem opisania komunikatów w operacjach jest użycie Stream klasy lub jednej z jej klas pochodnych w kontrakcie operacji lub jako składowa treści kontraktu komunikatu (musi być jedynym elementem członkowskim w tym przypadku). W przypadku komunikatów przychodzących typ musi mieć wartość Stream
— nie można używać klas pochodnych.
Zamiast wywoływania serializatora program WCF pobiera dane ze strumienia i umieszcza je bezpośrednio w wiadomości wychodzącej lub pobiera dane z komunikatu przychodzącego i umieszcza je bezpośrednio w strumieniu. W poniższym przykładzie pokazano użycie strumieni.
[OperationContract]
public Stream DownloadFile(string fileName);
<OperationContract()>
Function DownloadFile(fileName As String) As String
Nie można łączyć Stream
i nie przesyłać strumieniowo danych w jednej treści komunikatu. Użyj kontraktu komunikatów, aby umieścić dodatkowe dane w nagłówkach komunikatów. W poniższym przykładzie pokazano nieprawidłowe użycie strumieni podczas definiowania kontraktu operacji.
//Incorrect:
// [OperationContract]
// public void UploadFile (string fileName, Stream fileData);
'Incorrect:
'<OperationContract()>
Public Sub UploadFile(fileName As String, fileData As StreamingContext)
W poniższym przykładzie pokazano prawidłowe użycie strumieni podczas definiowania kontraktu operacji.
[OperationContract]
public void UploadFile (UploadFileMessage message);
//code omitted
[MessageContract]
public class UploadFileMessage
{
[MessageHeader] public string fileName;
[MessageBodyMember] public Stream fileData;
}
<OperationContract()>
Public Sub UploadFile(fileName As String, fileData As StreamingContext)
'Code Omitted
<MessageContract()>
Public Class UploadFileMessage
<MessageHeader()>
Public Property fileName As String
<MessageBodyMember()>
Public Property fileData As Stream
End Class
Aby uzyskać więcej informacji, zobacz Duże dane i przesyłanie strumieniowe.
Używanie klasy Message
Aby mieć pełną kontrolę programową nad komunikatami wysłanymi lub odebranych, możesz użyć Message klasy bezpośrednio, jak pokazano w poniższym przykładowym kodzie.
[OperationContract]
public void LogMessage(Message m);
<OperationContract()>
Sub LogMessage(m As Message)
Jest to zaawansowany scenariusz opisany szczegółowo w temacie Using the Message Class (Używanie klasy komunikatów).
Opisywanie komunikatów o błędach
Oprócz komunikatów, które są opisane przez wartość zwracaną i dane wyjściowe lub parametry odwołania, każda operacja, która nie jest jednokierunkowa, może zwrócić co najmniej dwa możliwe komunikaty: normalny komunikat odpowiedzi i komunikat o błędzie. Rozważmy następujący kontrakt operacji.
[OperationContract]
float GetAirfare(string fromCity, string toCity, DateTime date);
<OperationContract()>
Function GetAirfare(fromCity As String, toCity As String, date as DateTime)
Ta operacja może zwrócić normalny komunikat zawierający float
liczbę lub komunikat o błędzie zawierający kod błędu i opis. Można to zrobić, zgłaszając FaultException element w implementacji usługi.
Możesz określić dodatkowe możliwe komunikaty o błędach przy użyciu atrybutu FaultContractAttribute . Dodatkowe błędy muszą być serializowalne przy użyciu DataContractSerializerelementu , jak pokazano w poniższym przykładowym kodzie.
[OperationContract]
[FaultContract(typeof(ItineraryNotAvailableFault))]
float GetAirfare(string fromCity, string toCity, DateTime date);
//code omitted
[DataContract]
public class ItineraryNotAvailableFault
{
[DataMember]
public bool IsAlternativeDateAvailable;
[DataMember]
public DateTime alternativeSuggestedDate;
}
<OperationContract()>
<FaultContract(GetType(ItineraryNotAvailableFault))>
Function GetAirfare(fromCity As String, toCity As String, date as DateTime) As Double
'Code Omitted
<DataContract()>
Public Class
<DataMember()>
Public Property IsAlternativeDateAvailable As Boolean
<DataMember()>
Public Property alternativeSuggestedDate As DateTime
End Class
Te dodatkowe błędy można wygenerować, zgłaszając FaultException<TDetail> odpowiedni typ kontraktu danych. Aby uzyskać więcej informacji, zobacz Obsługa wyjątków i błędów.
Nie można użyć XmlSerializer klasy do opisania błędów. Nie XmlSerializerFormatAttribute ma to wpływu na umowy o błędy.
Używanie typów pochodnych
Możesz użyć typu podstawowego w operacji lub kontraktu komunikatu, a następnie użyć typu pochodnego podczas wywoływania operacji. W takim przypadku należy użyć atrybutu ServiceKnownTypeAttribute lub innego mechanizmu, aby umożliwić korzystanie z typów pochodnych. Rozważ następującą operację.
[OperationContract]
public bool IsLibraryItemAvailable(LibraryItem item);
<OperationContract()>
Function IsLibraryItemAvailable(item As LibraryItem) As Boolean
Załóżmy, że dwa typy Book
i Magazine
, pochodzą z LibraryItem
klasy . Aby użyć tych typów w IsLibraryItemAvailable
operacji, możesz zmienić operację w następujący sposób:
[OperationContract]
[ServiceKnownType(typeof(Book))]
[ServiceKnownType(typeof(Magazine))]
public bool IsLibraryItemAvailable(LibraryItem item);
Alternatywnie możesz użyć atrybutu KnownTypeAttribute , gdy jest używana wartość domyślna DataContractSerializer , jak pokazano w poniższym przykładowym kodzie.
[OperationContract]
public bool IsLibraryItemAvailable(LibraryItem item);
// code omitted
[DataContract]
[KnownType(typeof(Book))]
[KnownType(typeof(Magazine))]
public class LibraryItem
{
//code omitted
}
<OperationContract()>
Function IsLibraryItemAvailable(item As LibraryItem) As Boolean
'Code Omitted
<DataContract()>
<KnownType(GetType(Book))>
<KnownType(GetType(Magazine))>
Public Class LibraryItem
'Code Omitted
End Class
Atrybutu XmlIncludeAttribute można użyć podczas korzystania z elementu XmlSerializer.
Atrybut można zastosować ServiceKnownTypeAttribute do operacji lub do całej usługi. Akceptuje typ lub nazwę metody do wywołania w celu uzyskania listy znanych typów, podobnie jak KnownTypeAttribute atrybut. Aby uzyskać więcej informacji, zobacz Znane typy kontraktów danych.
Określanie stylu i użycia
Podczas opisywania usług przy użyciu języka opisu usług sieci Web (WSDL) dwa najczęściej używane style to Document i remote procedure call (RPC). W stylu dokumentu cała treść komunikatu jest opisana przy użyciu schematu, a plik WSDL opisuje różne części treści komunikatów, odwołując się do elementów w tym schemacie. W stylu RPC język WSDL odwołuje się do typu schematu dla każdej części komunikatu, a nie elementu. W niektórych przypadkach należy ręcznie wybrać jeden z tych stylów. Można to zrobić, stosując atrybut i ustawiając DataContractFormatAttributeStyle
właściwość (gdy DataContractSerializer element jest używany) lub ustawiając Style
atrybut XmlSerializerFormatAttribute (w przypadku używania XmlSerializerobiektu ).
Ponadto program XmlSerializer obsługuje dwie formy serializowanego kodu XML: Literal
i Encoded
. Literal
jest najczęściej akceptowanym formularzem i jest jedyną formą obsługiwaną DataContractSerializer przez program . Encoded
jest starszym formularzem opisanym w sekcji 5 specyfikacji protokołu SOAP i nie jest zalecany w przypadku nowych usług. Aby przełączyć się do Encoded
trybu, ustaw Use
właściwość atrybutu XmlSerializerFormatAttribute na Encoded
wartość .
W większości przypadków nie należy zmieniać ustawień domyślnych Style
właściwości i Use
.
Kontrolowanie procesu serializacji
Możesz wykonać wiele czynności, aby dostosować sposób serializacji danych.
Zmienianie Ustawienia serializacji serwera
Gdy wartość domyślna DataContractSerializer jest używana, możesz kontrolować niektóre aspekty procesu serializacji w usłudze, stosując ServiceBehaviorAttribute atrybut do usługi. W szczególności można użyć MaxItemsInObjectGraph
właściwości , aby ustawić limit przydziału, który ogranicza maksymalną liczbę obiektów DataContractSerializer deserializuje. Możesz użyć IgnoreExtensionDataObject
właściwości , aby wyłączyć funkcję przechowywania wersji w obie strony. Aby uzyskać więcej informacji na temat limitów przydziału, zobacz Zagadnienia dotyczące zabezpieczeń danych. Aby uzyskać więcej informacji na temat zaokrąglania, zobacz Kontrakty danych zgodne z przekazywaniem.
[ServiceBehavior(MaxItemsInObjectGraph=100000)]
public class MyDataService:IDataService
{
public DataPoint[] GetData()
{
// Implementation omitted
}
}
<ServiceBehavior(MaxItemsInObjectGraph:=100000)>
Public Class MyDataService Implements IDataService
Function GetData() As DataPoint()
‘ Implementation omitted
End Function
End Interface
Zachowania serializacji
W programie WCF są dostępne dwa zachowania, a DataContractSerializerOperationBehavior i XmlSerializerOperationBehavior , które są automatycznie podłączane w zależności od tego, który serializator jest używany do określonej operacji. Ponieważ te zachowania są stosowane automatycznie, zwykle nie trzeba ich znać.
Jednak element DataContractSerializerOperationBehavior
ma MaxItemsInObjectGraph
właściwości , IgnoreExtensionDataObject
i DataContractSurrogate
, których można użyć do dostosowania procesu serializacji. Pierwsze dwie właściwości mają takie samo znaczenie, jak omówiono w poprzedniej sekcji. Za pomocą DataContractSurrogate
właściwości można włączyć zastępcze kontrakty danych, które są zaawansowanym mechanizmem dostosowywania i rozszerzania procesu serializacji. Aby uzyskać więcej informacji, zobacz Data Contract Surrogates (Zastępcze kontrakty danych).
Możesz użyć polecenia DataContractSerializerOperationBehavior
, aby dostosować serializacji klienta i serwera. W poniższym przykładzie pokazano, jak zwiększyć MaxItemsInObjectGraph
limit przydziału na kliencie.
ChannelFactory<IDataService> factory = new ChannelFactory<IDataService>(binding, address);
foreach (OperationDescription op in factory.Endpoint.Contract.Operations)
{
DataContractSerializerOperationBehavior dataContractBehavior =
op.Behaviors.Find<DataContractSerializerOperationBehavior>()
as DataContractSerializerOperationBehavior;
if (dataContractBehavior != null)
{
dataContractBehavior.MaxItemsInObjectGraph = 100000;
}
}
IDataService client = factory.CreateChannel();
Dim factory As ChannelFactory(Of IDataService) = New ChannelFactory(Of IDataService)(binding, address)
For Each op As OperationDescription In factory.Endpoint.Contract.Operations
Dim dataContractBehavior As DataContractSerializerOperationBehavior = op.Behaviors.Find(Of DataContractSerializerOperationBehavior)()
If dataContractBehavior IsNot Nothing Then
dataContractBehavior.MaxItemsInObjectGraph = 100000
End If
Next
Dim client As IDataService = factory.CreateChannel
Poniższy kod jest odpowiednikiem w usłudze, w przypadku własnego przypadku:
ServiceHost serviceHost = new ServiceHost(typeof(IDataService))
foreach (ServiceEndpoint ep in serviceHost.Description.Endpoints)
{
foreach (OperationDescription op in ep.Contract.Operations)
{
DataContractSerializerOperationBehavior dataContractBehavior =
op.Behaviors.Find<DataContractSerializerOperationBehavior>()
as DataContractSerializerOperationBehavior;
if (dataContractBehavior != null)
{
dataContractBehavior.MaxItemsInObjectGraph = 100000;
}
}
}
serviceHost.Open();
Dim serviceHost As ServiceHost = New ServiceHost(GetType(IDataService))
For Each ep As ServiceEndpoint In serviceHost.Description.Endpoints
For Each op As OperationDescription In ep.Contract.Operations
Dim dataContractBehavior As DataContractSerializerOperationBehavior = op.Behaviors.Find(Of DataContractSerializerOperationBehavior)()
If dataContractBehavior IsNot Nothing Then
dataContractBehavior.MaxItemsInObjectGraph = 100000
End If
Next
Next
serviceHost.Open()
W przypadku hostowanym w Sieci Web należy utworzyć nową ServiceHost
klasę pochodną i użyć fabryki hostów usług, aby ją podłączyć.
Kontrolowanie Ustawienia serializacji w konfiguracji
Element MaxItemsInObjectGraph
i IgnoreExtensionDataObject
można kontrolować za pomocą konfiguracji przy użyciu punktu końcowego dataContractSerializer
lub zachowania usługi, jak pokazano w poniższym przykładzie.
<configuration>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="LargeQuotaBehavior">
<dataContractSerializer
maxItemsInObjectGraph="100000" />
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://example.com/myservice"
behaviorConfiguration="LargeQuotaBehavior"
binding="basicHttpBinding" bindingConfiguration=""
contract="IDataService"
name="" />
</client>
</system.serviceModel>
</configuration>
Serializacja typu współużytkowanego, zachowywanie grafu obiektów i niestandardowe serializatory
Serializuje DataContractSerializer przy użyciu nazw kontraktów danych, a nie nazw typów platformy .NET. Jest to zgodne z założeniami architektury zorientowanej na usługę i zapewnia dużą elastyczność — typy platformy .NET mogą ulec zmianie bez wpływu na kontrakt przewodowy. W rzadkich przypadkach można serializować rzeczywiste nazwy typów platformy .NET, wprowadzając w ten sposób ścisłe sprzężenie między klientem a serwerem, podobnie jak technologia komunikacji wirtualnej programu .NET Framework. Nie jest to zalecana praktyka, z wyjątkiem rzadkich przypadków, które zwykle występują podczas migracji do programu WCF z komunikacji wirtualnej programu .NET Framework. W takim przypadku należy użyć NetDataContractSerializer klasy zamiast DataContractSerializer klasy .
Zwykle DataContractSerializer serializuje wykresy obiektów jako drzewa obiektów. Oznacza to, że jeśli ten sam obiekt jest określany więcej niż raz, jest serializowany więcej niż raz. Rozważmy na przykład PurchaseOrder
wystąpienie z dwoma polami typu Address o nazwie billTo
i shipTo
. Jeśli oba pola są ustawione na to samo wystąpienie adresu, istnieją dwa identyczne wystąpienia adresów po serializacji i deserializacji. Dzieje się tak, ponieważ nie ma standardowego sposobu współdziałania w celu reprezentowania grafów obiektów w formacie XML (z wyjątkiem starszego standardu zakodowanego przez protokół SOAP dostępnego w XmlSerializersystemie , zgodnie z opisem w poprzedniej sekcji i Style
Use
). Serializowanie grafów obiektów, ponieważ drzewa mają pewne wady, na przykład wykresy z odwołaniami okrągłymi nie mogą być serializowane. Czasami konieczne jest przełączenie się na serializacji grafu obiektów true, mimo że nie jest to możliwe do współdziałania. Można to zrobić przy użyciu DataContractSerializer konstrukcji z parametrem ustawionym preserveObjectReferences
na true
wartość .
Czasami wbudowane serializatory nie są wystarczające dla danego scenariusza. W większości przypadków nadal można użyć XmlObjectSerializer abstrakcji, z której pochodzą zarówno klasy DataContractSerializer , jak i NetDataContractSerializer .
Poprzednie trzy przypadki (zachowywanie typu platformy.NET, zachowywanie grafu obiektów i całkowicie niestandardowa XmlObjectSerializer
serializacja) wymagają podłączenia niestandardowego serializatora. W tym celu wykonaj następujące czynności:
Napisz własne zachowanie pochodzące z elementu DataContractSerializerOperationBehavior.
Zastąp dwie
CreateSerializer
metody, aby zwrócić własny serializator ( NetDataContractSerializerz wartością , DataContractSerializer ustawionąpreserveObjectReferences
natrue
, lub własną niestandardową XmlObjectSerializer).Przed otwarciem hosta usługi lub utworzeniem kanału klienta usuń istniejące DataContractSerializerOperationBehavior zachowanie i podłącz niestandardową klasę pochodną utworzoną w poprzednich krokach.
Aby uzyskać więcej informacji na temat zaawansowanych pojęć serializacji, zobacz Serializacja i Deserializacja.