Delen via


DataContract Surrogaat

Het DataContract-voorbeeld laat zien hoe processen zoals serialisatie, deserialisatie, schema-export en schemaimport kunnen worden aangepast met behulp van een surrogaatklasse voor gegevenscontracten. In dit voorbeeld ziet u hoe u een surrogaat gebruikt in een client- en serverscenario waarin gegevens worden geserialiseerd en verzonden tussen een WCF-client (Windows Communication Foundation) en -service.

Notitie

De installatieprocedure en build-instructies voor dit voorbeeld bevinden zich aan het einde van dit onderwerp.

In het voorbeeld wordt het volgende servicecontract gebruikt:

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

    [OperationContract]
    Employee GetEmployee(string name);
}

Met de AddEmployee bewerking kunnen gebruikers gegevens over nieuwe werknemers toevoegen en de GetEmployee bewerking ondersteunt het zoeken naar werknemers op basis van naam.

Voor deze bewerkingen wordt het volgende gegevenstype gebruikt:

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

    [DataMember]
    public Decimal salary;

    [DataMember]
    public Person person;
}

In het Employee type kan de Person klasse (weergegeven in de volgende voorbeeldcode) niet worden geserialiseerd omdat DataContractSerializer deze geen geldige gegevenscontractklasse is.

public class Person
{
    public string firstName;

    public string lastName;

    public int age;

    public Person() { }
}

U kunt het DataContractAttribute kenmerk toepassen op de Person klasse, maar dit is niet altijd mogelijk. De Person klasse kan bijvoorbeeld worden gedefinieerd in een afzonderlijke assembly waarvoor u geen controle hebt.

Gezien deze beperking, is een manier om de Person klasse te serialiseren door een andere klasse die is gemarkeerd met DataContractAttribute en kopieert over de benodigde gegevens naar de nieuwe klasse. Het doel is om de Person klasse te laten verschijnen als een DataContract aan de DataContractSerializer. Houd er rekening mee dat dit een manier is om niet-gegevenscontractklassen te serialiseren.

Het voorbeeld vervangt de klasse logisch door een andere klasse met de Person naam PersonSurrogated.

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

    [DataMember]
    public string LastName;

    [DataMember]
    public int Age;
}

Het gegevenscontract surrogaat wordt gebruikt om deze vervanging te bereiken. Een gegevenscontract surrogaat is een klasse die implementeert IDataContractSurrogate. In dit voorbeeld implementeert de AllowNonSerializableTypesSurrogate klasse deze interface.

In de interface-implementatie is de eerste taak het instellen van een typetoewijzing van Person naar PersonSurrogated. Dit wordt zowel bij serialisatietijd als bij het exporteren van schema's gebruikt. Deze toewijzing wordt bereikt door de GetDataContractType(Type) methode te implementeren.

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

De GetObjectToSerialize(Object, Type) methode wijst een Person exemplaar toe aan een PersonSurrogated exemplaar tijdens de serialisatie, zoals wordt weergegeven in de volgende voorbeeldcode.

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

De GetDeserializedObject(Object, Type) methode biedt de omgekeerde toewijzing voor deserialisatie, zoals wordt weergegeven in de volgende voorbeeldcode.

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

Als u het gegevenscontract wilt toewijzen aan de bestaande Person klasse tijdens het PersonSurrogated importeren van het schema, implementeert het voorbeeld de GetReferencedTypeOnImport(String, String, Object) methode, zoals wordt weergegeven in de volgende voorbeeldcode.

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

Met de volgende voorbeeldcode wordt de implementatie van de IDataContractSurrogate interface voltooid.

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 dit voorbeeld is de surrogaat ingeschakeld in ServiceModel door een kenmerk met de naam AllowNonSerializableTypesAttribute. Ontwikkelaars moeten dit kenmerk toepassen op hun servicecontract, zoals wordt weergegeven in het IPersonnelDataService bovenstaande servicecontract. Met dit kenmerk wordt IContractBehavior het surrogaat geïmplementeerd en ingesteld op bewerkingen in ApplyClientBehavior de en ApplyDispatchBehavior methoden.

Het kenmerk is in dit geval niet nodig. Het wordt gebruikt voor demonstratiedoeleinden in dit voorbeeld. Gebruikers kunnen een surrogaat ook inschakelen door handmatig een vergelijkbare IContractBehaviortoe te voegen, IEndpointBehavior of IOperationBehavior door code of configuratie te gebruiken.

De IContractBehavior implementatie zoekt naar bewerkingen die Gebruikmaken van DataContract door te controleren of ze een geregistreerde bewerking DataContractSerializerOperationBehavior hebben. Als dat het gebeurt, wordt de DataContractSurrogate eigenschap voor dat gedrag ingesteld. In de volgende voorbeeldcode ziet u hoe dit wordt gedaan. Als u de surrogaat instelt op dit bewerkingsgedrag, kan deze worden geserialiseerd en gedeserialiseerd.

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();
    }
}

Er moeten extra stappen worden uitgevoerd om het surrogaat in te voegen voor gebruik tijdens het genereren van metagegevens. Eén mechanisme om dit te doen, is door een IWsdlExportExtension voorbeeld te bieden dat in dit voorbeeld wordt gedemonstreert. Een andere manier is om de WsdlExporter rechtstreeks te wijzigen.

Het AllowNonSerializableTypesAttribute kenmerk implementeert IWsdlExportExtension en IContractBehavior. De extensie kan een IContractBehavior of IEndpointBehavior in dit geval zijn. De IWsdlExportExtension.ExportContract methode-implementatie maakt het mogelijk om het surrogaat toe te voegen aan de gebruikte methode tijdens het XsdDataContractExporter genereren van het schema voor DataContract. In het volgende codefragment ziet u hoe u dit doet.

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();
}

Wanneer u het voorbeeld uitvoert, roept de client AddEmployee aan, gevolgd door een GetEmployee-aanroep om te controleren of de eerste aanroep is geslaagd. Het resultaat van de getEmployee-bewerkingsaanvraag wordt weergegeven in het clientconsolevenster. De bewerking GetEmployee moet slagen om de werknemer te vinden en 'gevonden' af te drukken.

Notitie

In dit voorbeeld ziet u hoe u een surrogaat kunt aansluiten voor het serialiseren, deserialiseren en genereren van metagegevens. Er wordt niet getoond hoe u een surrogaat kunt aansluiten voor het genereren van code uit metagegevens. Zie het voorbeeld van de aangepaste WSDL-publicatie voor een voorbeeld van hoe een surrogaat kan worden gebruikt voor het genereren van clientcode.

Het voorbeeld instellen, compileren en uitvoeren

  1. Zorg ervoor dat u de eenmalige installatieprocedure voor de Windows Communication Foundation-voorbeelden hebt uitgevoerd.

  2. Volg de instructies in Het bouwen van de Windows Communication Foundation-voorbeelden om de C#-editie van de oplossing te bouwen.

  3. Als u het voorbeeld wilt uitvoeren in een configuratie met één of meerdere computers, volgt u de instructies in Het uitvoeren van de Windows Communication Foundation-voorbeelden.