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 IContractBehavior
toe 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
Zorg ervoor dat u de eenmalige installatieprocedure voor de Windows Communication Foundation-voorbeelden hebt uitgevoerd.
Volg de instructies in Het bouwen van de Windows Communication Foundation-voorbeelden om de C#-editie van de oplossing te bouwen.
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.