Sdílet prostřednictvím


Náhrada kontraktu dat

Ukázka DataContract ukazuje, jak lze procesy, jako je serializace, deserializace, export schématu a import schématu, přizpůsobit pomocí náhradní třídy kontraktu dat. Tato ukázka ukazuje, jak použít náhradník ve scénáři klienta a serveru, kde se data serializují a přenášejí mezi klientem a službou WCF (Windows Communication Foundation).

Poznámka:

Postup nastavení a pokyny k sestavení pro tuto ukázku najdete na konci tohoto tématu.

Ukázka používá následující kontrakt služby:

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

    [OperationContract]
    Employee GetEmployee(string name);
}

Tato AddEmployee operace umožňuje uživatelům přidávat data o nových zaměstnancích a GetEmployee operace podporuje vyhledávání zaměstnanců na základě jména.

Tyto operace používají následující datový typ:

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

    [DataMember]
    public Decimal salary;

    [DataMember]
    public Person person;
}

Employee V tomto typu Person nelze serializovat DataContractSerializer třídu (zobrazenou v následujícím vzorovém kódu), protože není platnou třídou kontraktu dat.

public class Person
{
    public string firstName;

    public string lastName;

    public int age;

    public Person() { }
}

Atribut můžete použít DataContractAttribute pro Person třídu, ale to není vždy možné. Třída může být například Person definována v samostatném sestavení, nad kterým nemáte žádný ovládací prvek.

Vzhledem k tomuto omezení je jedním ze způsobů, jak serializovat Person třídu, je nahradit jinou třídou, která je označena DataContractAttribute a zkopírována nad potřebnými daty do nové třídy. Cílem je, aby Person se třída objevila jako DataContract na DataContractSerializer. Všimněte si, že toto je jeden ze způsobů, jak serializovat třídy bez datového kontraktu.

Ukázka logicky nahradí Person třídu jinou třídou s názvem PersonSurrogated.

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

    [DataMember]
    public string LastName;

    [DataMember]
    public int Age;
}

Náhradní kontrakt dat se používá k dosažení této náhrady. Náhradní kontrakt dat je třída, která implementuje IDataContractSurrogate. V této ukázce AllowNonSerializableTypesSurrogate třída implementuje toto rozhraní.

V implementaci rozhraní je prvním úkolem vytvořit mapování typu z Person do PersonSurrogated. Používá se při serializaci i v době exportu schématu. Toto mapování se dosahuje implementací GetDataContractType(Type) metody.

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

GetObjectToSerialize(Object, Type) Metoda mapuje Person instanci na PersonSurrogated instanci během serializace, jak je znázorněno v následujícím vzorovém kódu.

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

Metoda GetDeserializedObject(Object, Type) poskytuje zpětné mapování pro deserializaci, jak je znázorněno v následujícím vzorovém kódu.

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

Pokud chcete mapovat PersonSurrogated kontrakt dat na existující Person třídu během importu schématu, ukázka implementuje metodu GetReferencedTypeOnImport(String, String, Object) , jak je znázorněno v následujícím vzorovém kódu.

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

Následující ukázkový kód dokončí implementaci IDataContractSurrogate rozhraní.

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

V této ukázce je náhradní položka povolena v ServiceModel atributem s názvem AllowNonSerializableTypesAttribute. Vývojáři by tento atribut potřebovali použít u kontraktu služeb, jak je znázorněno na výše uvedeném kontraktu IPersonnelDataService služby. Tento atribut implementuje IContractBehavior a nastavuje náhradní operace ve svých ApplyClientBehavior a ApplyDispatchBehavior metodách.

V tomto případě není atribut nutný – používá se pro demonstrační účely v této ukázce. Uživatelé můžou alternativně povolit náhradu ručním přidáním podobného IContractBehaviorIEndpointBehavior kódu nebo IOperationBehavior pomocí kódu nebo pomocí konfigurace.

Implementace IContractBehavior hledá operace, které používají DataContract kontrolou, jestli mají zaregistrované DataContractSerializerOperationBehavior . Pokud ano, nastaví DataContractSurrogate vlastnost pro toto chování. Následující ukázkový kód ukazuje, jak se to dělá. Nastavení náhradního přístupu k tomuto chování operace umožňuje serializaci a deserializaci.

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

Je potřeba provést další kroky pro připojení náhradních dat pro použití během generování metadat. Jedním z mechanismů, jak to udělat, je poskytnout IWsdlExportExtension to, co tato ukázka demonstruje. Dalším způsobem je úprava WsdlExporter přímo.

Atribut AllowNonSerializableTypesAttribute implementuje IWsdlExportExtension a IContractBehavior. Rozšíření může být buď an IContractBehavior , nebo IEndpointBehavior v tomto případě. Její IWsdlExportExtension.ExportContract implementace metody umožňuje náhradní přidáním do XsdDataContractExporter použitého během generování schématu pro DataContract. Následující fragment kódu ukazuje, jak to udělat.

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

Když spustíte ukázku, klient zavolá AddEmployee následovaný voláním GetEmployeee, které zkontroluje, jestli bylo první volání úspěšné. Výsledek požadavku operace GetEmployeee se zobrazí v okně konzoly klienta. Operace GetEmployee musí být úspěšná při hledání zaměstnance a tisku "found".

Poznámka:

Tato ukázka ukazuje, jak připojit náhradní položky pro serializaci, deserializaci a generování metadat. Nezobrazuje, jak připojit náhradní kód pro generování kódu z metadat. Pokud se chcete podívat na ukázku toho, jak se dá náhradník použít k připojení ke generování kódu klienta, podívejte se na ukázku vlastní publikace WSDL.

Nastavení, sestavení a spuštění ukázky

  1. Ujistěte se, že jste pro ukázky windows Communication Foundation provedli jednorázovou instalační proceduru.

  2. Pokud chcete sestavit edici jazyka C# řešení, postupujte podle pokynů v části Sestavení ukázek Windows Communication Foundation.

  3. Pokud chcete spustit ukázku v konfiguraci s jedním nebo více počítači, postupujte podle pokynů v části Spuštění ukázek windows Communication Foundation.