DataContract-ErsatzzeichenDataContract Surrogate

In diesem Beispiel wird beschrieben, wie Vorgänge wie Serialisierung, Deserialisierung, Schemaexport und Schemaimport mithilfe einer Datenvertrag-Ersatzzeichenklasse angepasst werden können.This sample demonstrates how processes like serialization, deserialization, schema export, and schema import can be customized using a data contract surrogate class. Dieses Beispiel zeigt, wie ein Ersatzzeichen in einem Client und Server-Szenario, in dem Daten serialisiert und zwischen Windows Communication Foundation (WCF)-Client und Dienst übertragen.This sample shows how to use a surrogate in a client and server scenario where data is serialized and transmitted between a Windows Communication Foundation (WCF) client and service.

Hinweis

Die Setupprozedur und die Buildanweisungen für dieses Beispiel befinden sich am Ende dieses Themas.The setup procedure and build instructions for this sample are located at the end of this topic.

Im Beispiel wird der folgende Dienstvertrag verwendet.The sample uses the following service contract:

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]  
[AllowNonSerializableTypes]  
public interface IPersonnelDataService  
{  
    [OperationContract]  
    void AddEmployee(Employee employee);  

    [OperationContract]  
    Employee GetEmployee(string name);  
}  

Mit dem AddEmployee-Vorgang können Benutzer Daten zu neuen Mitarbeitern hinzufügen. Der GetEmployee-Vorgang unterstützt das Suchen von Mitarbeitern nach Namen.The AddEmployee operation allows users to add data about new employees and the GetEmployee operation supports search for employees based on name.

In diesen Vorgängen wird der folgende Datentyp verwendet:These operations use the following data type:

[DataContract(Namespace = "http://Microsoft.ServiceModel.Samples")]  
class Employee  
{  
    [DataMember]  
    public DateTime dateHired;  

    [DataMember]  
    public Decimal salary;  

    [DataMember]  
    public Person person;  
}  

Im Employee-Typ kann die Person-Klasse (im folgenden Beispielcode dargestellt) nicht von DataContractSerializer serialisiert werden, da es sich nicht um eine gültige Datenvertragsklasse handelt.In the Employee type, the Person class (shown in the following sample code) cannot be serialized by the DataContractSerializer because it is not a valid data contract class.

public class Person  
{  
    public string firstName;  

    public string lastName;  

    public int age;  

    public Person() { }  
}  

Sie können das DataContract-Attribut auf die Person-Klasse anwenden, dies ist jedoch nicht immer möglich.You can apply the DataContract attribute to the Person class, but this is not always possible. Die Person-Klasse kann beispielsweise in einer separaten Assembly definiert sein, auf die Sie keinen Einfluss haben.For example, the Person class can be defined in a separate assembly over which you have no control.

Wenn diese Einschränkung vorliegt, besteht eine Möglichkeit zum Serialisieren der Person-Klasse darin, sie durch eine andere Klasse zu ersetzen, die mit DataContractAttribute markiert ist, und erforderliche Daten in die neue Klasse zu kopieren.Given this restriction, one way to serialize the Person class is to substitute it with another class that is marked with DataContractAttribute and copy over necessary data to the new class. Das Ziel ist dabei, die Person-Klasse für DataContractSerializer als DataContract erscheinen zu lassen.The objective is to make the Person class appear as a DataContract to the DataContractSerializer. Beachten Sie, dass dies eine Möglichkeit zum Serialisieren von Klassen ist, bei denen es sich nicht um Datenvertragsklassen handelt.Note that this is one way to serialize non-data contract classes.

Im Beispiel wird die Person-Klasse logisch durch eine andere Klasse namens PersonSurrogated ersetzt.The sample logically replaces the Person class with a different class named PersonSurrogated.

[DataContract(Name="Person", Namespace = "http://Microsoft.ServiceModel.Samples")]  
public class PersonSurrogated  
{  
    [DataMember]  
    public string FirstName;  

    [DataMember]  
    public string LastName;  

    [DataMember]  
    public int Age;  
}  

Zum Durchführen dieser Ersetzung wird das Datenvertrag-Ersatzzeichen verwendet.The data contract surrogate is used to achieve this replacement. Ein Datenvertrag-Ersatzzeichen ist eine Klasse, die IDataContractSurrogate implementiert.A data contract surrogate is a class that implements IDataContractSurrogate. In diesem Beispiel implementiert die AllowNonSerializableTypesSurrogate-Klasse diese Schnittstelle.In this sample, the AllowNonSerializableTypesSurrogate class implements this interface.

In der Schnittstellenimplementierung ist die erste Aufgabe das Einrichten einer Typzuordnung von Person zu PersonSurrogated.In the interface implementation, the first task is to establish a type mapping from Person to PersonSurrogated. Dies wird bei der Serialisierung sowie beim Schemaexport verwendet.This is used both at serialization time as well as at schema export time. Diese Zuordnung erfolgt durch das Implementieren der GetDataContractType(Type)-Methode.This mapping is achieved by implementing the GetDataContractType(Type) method.

public Type GetDataContractType(Type type)  
{  
    if (typeof(Person).IsAssignableFrom(type))  
    {  
        return typeof(PersonSurrogated);  
    }  
    return type;  
}  

Die GetObjectToSerialize(Object, Type)-Methode ordnet bei der Serialisierung eine Person-Instanz einer PersonSurrogated-Instanz zu, wie im folgenden Beispielcode dargestellt.The GetObjectToSerialize(Object, Type) method maps a Person instance to a PersonSurrogated instance during serialization, as shown in the following sample code.

public object GetObjectToSerialize(object obj, Type targetType)  
{  
    if (obj is Person)  
    {  
        Person person = (Person)obj;  
        PersonSurrogated personSurrogated = new PersonSurrogated();  
        personSurrogated.FirstName = person.firstName;  
        personSurrogated.LastName = person.lastName;  
        personSurrogated.Age = person.age;  
        return personSurrogated;  
    }  
    return obj;  
}  

Die GetDeserializedObject(Object, Type)-Methode stellt die umgekehrte Zuordnung für die Deserialisierung bereit, wie im folgenden Beispielcode gezeigt.The GetDeserializedObject(Object, Type) method provides the reverse mapping for deserialization, as shown in the following sample code.

public object GetDeserializedObject(object obj,   
Type targetType)  
{  
    if (obj is PersonSurrogated)  
    {  
        PersonSurrogated personSurrogated = (PersonSurrogated)obj;  
        Person person = new Person();  
        person.firstName = personSurrogated.FirstName;  
        person.lastName = personSurrogated.LastName;  
        person.age = personSurrogated.Age;  
        return person;  
    }  
    return obj;  
}  

Zum Zuordnen des PersonSurrogated-Datenvertrags zu der vorhandenen Person-Klasse beim Schemaimport wird im Beispiel die GetReferencedTypeOnImport(String, String, Object)-Methode implementiert, wie im folgenden Beispielcode veranschaulicht.To map the PersonSurrogated data contract to the existing Person class during schema import, the sample implements the GetReferencedTypeOnImport(String, String, Object) method, as shown in the following sample code.

public Type GetReferencedTypeOnImport(string typeName,   
               string typeNamespace, object customData)  
{  
if (  
typeNamespace.Equals("http://schemas.datacontract.org/2004/07/DCSurrogateSample")  
)  
    {  
         if (typeName.Equals("PersonSurrogated"))  
        {  
             return typeof(Person);  
        }  
     }  
     return null;  
}  

Im folgenden Beispielcode wird die Implementierung der IDataContractSurrogate-Schnittstelle abgeschlossen.The following sample code completes the implementation of the IDataContractSurrogate interface.

public System.CodeDom.CodeTypeDeclaration ProcessImportedType(  
          System.CodeDom.CodeTypeDeclaration typeDeclaration,   
          System.CodeDom.CodeCompileUnit compileUnit)  
{  
    return typeDeclaration;  
}  
public object GetCustomDataToExport(Type clrType,   
                               Type dataContractType)  
{  
    return null;  
}  

public object GetCustomDataToExport(  
System.Reflection.MemberInfo memberInfo, Type dataContractType)  
{  
    return null;  
}  
public void GetKnownCustomDataTypes(  
        KnownTypeCollection customDataTypes)  
{  
    // It does not matter what we do here.  
    throw new NotImplementedException();  
}  

In diesem Beispiel wird das Ersatzzeichen in ServiceModel von dem Attribut AllowNonSerializableTypesAttribute aktiviert.In this sample, the surrogate is enabled in ServiceModel by an attribute called AllowNonSerializableTypesAttribute. Entwickler müssten dieses Attribut auf ihren Dienstvertrag anwenden, wie oben im IPersonnelDataService-Dienstvertrag dargestellt.Developers would need to apply this attribute on their service contract as shown on the IPersonnelDataService service contract above. Dieses Attribut implementiert IContractBehavior und richtet das Ersatzzeichen bei Vorgängen in der ApplyClientBehavior-Methode und der ApplyDispatchBehavior-Methode ein.This attribute implements IContractBehavior and sets up the surrogate on operations in its ApplyClientBehavior and ApplyDispatchBehavior methods.

Das Attribut ist in diesem Fall nicht erforderlich. Es wird in diesem Beispiel nur zur Veranschaulichung verwendet.The attribute is not necessary in this case - it is used for demonstration purposes in this sample. Die Benutzer können ein Ersatzzeichen auch aktivieren, indem sie mithilfe von Code oder Konfiguration ein ähnliches IContractBehavior, IEndpointBehavior oder IOperationBehavior hinzufügen.Users can alternatively enable a surrogate by manually adding a similar IContractBehavior, IEndpointBehavior or IOperationBehavior using code or using configuration.

Die IContractBehavior-Implementierung sucht nach Vorgängen, die DataContract verwenden, indem überprüft wird, ob DataContractSerializerOperationBehavior registriert ist.The IContractBehavior implementation looks for operations that use DataContract by checking if they have a DataContractSerializerOperationBehavior registered. Wenn dies der Fall ist, wird die DataContractSurrogate-Eigenschaft auf dieses Verhalten festgelegt.If they do, it sets the DataContractSurrogate property on that behavior. Der folgende Beispielcode zeigt die Vorgehensweise.The following sample code shows how this is done. Durch das Festlegen des Ersatzzeichens auf dieses Vorgangsverhalten wird es für die Serialisierung und die Deserialisierung aktiviert.Setting the surrogate on this operation behavior enables it for serialization and deserialization.

public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime proxy)  
{  
    foreach (OperationDescription opDesc in description.Operations)  
    {  
        ApplyDataContractSurrogate(opDesc);  
    }  
}  

public void ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatch)  
{  
    foreach (OperationDescription opDesc in description.Operations)  
    {  
        ApplyDataContractSurrogate(opDesc);  
    }  
}  

private static void ApplyDataContractSurrogate(OperationDescription description)  
{  
    DataContractSerializerOperationBehavior dcsOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();  
    if (dcsOperationBehavior != null)  
    {  
        if (dcsOperationBehavior.DataContractSurrogate == null)  
            dcsOperationBehavior.DataContractSurrogate = new AllowNonSerializableTypesSurrogate();  
    }  
}  

Damit das Ersatzzeichen für die Verwendung bei der Metadaten-Generierung eingebunden werden kann, sind zusätzliche Schritte erforderlich.Additional steps need to be taken to plug in the surrogate for use during metadata generation. Ein Mechanismus hierfür ist das Bereitstellen einer IWsdlExportExtension. Dies wird in diesem Beispiel veranschaulicht.One mechanism to do this is to provide an IWsdlExportExtension which is what this sample demonstrates. Eine andere Möglichkeit ist das direkte Ändern von WsdlExporter.Another way is to modify the WsdlExporter directly.

Die AllowNonSerializableTypesAttribute -Attribut implementiert IWsdlExportExtension und IContractBehavior.The AllowNonSerializableTypesAttribute attribute implements IWsdlExportExtension and IContractBehavior. Die Erweiterung kann es sich um eine IContractBehavior oder IEndpointBehavior in diesem Fall.The extension can be either an IContractBehavior or IEndpointBehavior in this case. Die Implementierung der IWsdlExportExtension.ExportContract-Methode aktiviert das Ersatzzeichen, indem es dem bei der Schemagenerierung für DataContract verwendeten XsdDataContractExporter hinzugefügt wird.Its IWsdlExportExtension.ExportContract method implementation enables the surrogate by adding it to the XsdDataContractExporter used during schema generation for DataContract. Der folgende Codeausschnitt veranschaulicht, wie Sie dabei vorgehen müssen:The following code snippet shows how to do this.

public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)  
{  
    if (exporter == null)  
        throw new ArgumentNullException("exporter");  

    object dataContractExporter;  
    XsdDataContractExporter xsdDCExporter;  
    if (!exporter.State.TryGetValue(typeof(XsdDataContractExporter), out dataContractExporter))  
    {  
        xsdDCExporter = new XsdDataContractExporter(exporter.GeneratedXmlSchemas);  
        exporter.State.Add(typeof(XsdDataContractExporter), xsdDCExporter);  
    }  
    else  
    {  
        xsdDCExporter = (XsdDataContractExporter)dataContractExporter;  
    }  
    if (xsdDCExporter.Options == null)  
        xsdDCExporter.Options = new ExportOptions();  

    if (xsdDCExporter.Options.DataContractSurrogate == null)  
        xsdDCExporter.Options.DataContractSurrogate = new AllowNonSerializableTypesSurrogate();  
}  

Wenn Sie das Beispiel ausführen, ruft der Client AddEmployee auf. Danach folgt ein Aufruf von GetEmployee, um zu überprüfen, ob der erste Aufruf erfolgreich war.When you run the sample, the client calls AddEmployee followed by a GetEmployee call to check if the first call was successful. Das Ergebnis der GetEmployee-Vorgangsanforderung wird im Clientkonsolenfenster angezeigt.The result of the GetEmployee operation request is displayed in the client console window. Der GetEmployee-Vorgang muss erfolgreich sein, den Mitarbeiter und Drucken "gefunden".The GetEmployee operation must succeed in finding the employee and print "found".

Hinweis

In diesem Beispiel wird das Einbinden eines Ersatzzeichens zum Serialisieren, Deserialisieren und für die Metadatengenerierung veranschaulicht.This sample shows how to plug in a surrogate for serialize, deserialize and metadata generation. Das Einbinden eines Ersatzzeichens für die Codegenerierung aus Metadaten wird nicht dargestellt.It does not show how to plug in a surrogate for code generation from metadata. Ein Beispiel, wie ein Ersatzzeichen verwendet werden kann, um in clientcodegenerierung eingebunden werden, finden Sie unter der benutzerdefinierte WSDL-Veröffentlichung Beispiel.To see a sample of how a surrogate can be used to plug into client code generation, see the Custom WSDL Publication sample.

So können Sie das Beispiel einrichten, erstellen und ausführenTo set up, build, and run the sample

  1. Stellen Sie sicher, dass Sie ausgeführt haben die Setupprozedur für die Windows Communication Foundation-Beispiele zum einmaligen.Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.

  2. Führen Sie zum Erstellen der C#-Edition der Lösung die Anweisungen im Erstellen der Windows Communication Foundation-Beispiele.To build the C# edition of the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  3. Um das Beispiel in einer einzelnen oder computerübergreifenden Konfiguration ausführen möchten, folgen Sie den Anweisungen Ausführen der Windows Communication Foundation-Beispiele.To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

Wichtig

Die Beispiele sind möglicherweise bereits auf dem Computer installiert.The samples may already be installed on your machine. Suchen Sie nach dem folgenden Verzeichnis (Standardverzeichnis), bevor Sie fortfahren.Check for the following (default) directory before continuing.

<InstallDrive>:\WF_WCF_Samples

Wenn dieses Verzeichnis nicht vorhanden ist, fahren Sie mit Windows Communication Foundation (WCF) und Windows Workflow Foundation (WF) Samples for .NET Framework 4 aller Windows Communication Foundation (WCF) herunterladen und WFWF Beispiele.If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF) and WFWF samples. Dieses Beispiel befindet sich im folgenden Verzeichnis.This sample is located in the following directory.

<InstallDrive>:\WF_WCF_Samples\WCF\Extensibility\DataContract

Siehe auchSee Also