このサンプルでは、シリアル化、逆シリアル化、スキーマのエクスポート、スキーマのインポートなどのプロセスを、データ コントラクト サロゲート クラスを使用してカスタマイズする方法を示します。このサンプルでは、クライアントとサーバーのシナリオ内でサロゲートを使用する方法を示します。このシナリオでは、データがシリアル化され、Windows Communication Foundation (WCF) クライアントとサービス間で転送が行われます。
![]() |
---|
このサンプルのセットアップ手順とビルド手順については、このトピックの最後を参照してください。 |
このサンプルでは、次のサービス コントラクトを使用します。
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
[AllowNonSerializableTypes]
public interface IPersonnelDataService
{
[OperationContract]
void AddEmployee(Employee employee);
[OperationContract]
Employee GetEmployee(string name);
}
AddEmployee
操作は、ユーザーが新しい従業員に関するデータを追加できるようにし、GetEmployee
操作は名前に基づく従業員の検索をサポートします。
これらの操作では、次のデータ型を使用します。
[DataContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
class Employee
{
[DataMember]
public DateTime dateHired;
[DataMember]
public Decimal salary;
[DataMember]
public Person person;
}
Employee
型では、Person
クラス (次のサンプル コードを参照) は有効なデータ コントラクト クラスではないので、DataContractSerializer によってシリアル化できません。
public class Person
{
public string firstName;
public string lastName;
public int age;
public Person() { }
}
DataContract
属性は Person
クラスに適用できますが、適用できない場合もあります。たとえば、Person
クラスは、ユーザーが制御できない別のアセンブリで定義することができます。
このような制限がある場合、Person
クラスをシリアル化するには、このクラスを DataContractAttribute
でマークされた別のクラスに置き換え、必要なデータをこの新しいクラスにコピーするという方法があります。この目的は、Person
クラスを DataContract として DataContractSerializer に表示することです。これは、データ コントラクト クラス以外のクラスをシリアル化する 1 つの方法です。
このサンプルでは、 Person
クラスを PersonSurrogated
という別のクラスに論理的に置き換えます。
[DataContract(Name="Person", Namespace = "http://Microsoft.ServiceModel.Samples")]
public class PersonSurrogated
{
[DataMember]
public string FirstName;
[DataMember]
public string LastName;
[DataMember]
public int Age;
}
データ コントラクト サロゲートは、この置き換えを実現するために使用されます。データ コントラクト サロゲートは、IDataContractSurrogate を実装するクラスです。このサンプルでは、AllowNonSerializableTypesSurrogate
クラスがこのインターフェイスを実装しています。
このインターフェイスの実装での最初のタスクは、Person
から PersonSurrogated
への型のマップを確立することです。これは、シリアル化の時点およびスキーマをエクスポートする時点の両方で使用されます。このマッピングは、GetDataContractType メソッドを実装することによって実現されます。
public Type GetDataContractType(Type type)
{
if (typeof(Person).IsAssignableFrom(type))
{
return typeof(PersonSurrogated);
}
return type;
}
GetObjectToSerialize メソッドは、シリアル化中に Person
インスタンスを PersonSurrogated
インスタンスにマップします。次のサンプル コードを参照してください。
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;
}
GetDeserializedObject メソッドは、逆シリアル化のための逆マップを実現します。次のサンプル コードを参照してください。
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;
}
スキーマのインポート中に PersonSurrogated
データ コントラクトを既存の Person
クラスにマップするため、このサンプルでは GetReferencedTypeOnImport メソッドを実装しています。次のサンプル コードを参照してください。
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;
}
IDataContractSurrogate インターフェイスの実装を完了するサンプル コードを次に示します。
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();
}
このサンプルでは、AllowNonSerializableTypesAttribute
という属性により、ServiceModel でサロゲートが有効になります。開発の際には、この属性をサービス コントラクトに適用する必要があります。上の IPersonnelDataService
サービス コントラクトを参照してください。この属性は IContractBehavior
を実装し、ApplyClientBehavior
メソッドと ApplyDispatchBehavior
メソッドでの操作にサロゲートを設定します。
この場合、この属性は必要ありません。このサンプルでのデモンストレーション用にのみ使用されます。これ以外の方法として、コードまたは構成を使用して同様の IContractBehavior
、IEndpointBehavior
、または IOperationBehavior
を手動で追加することにより、サロゲートを有効にすることもできます。
IContractBehavior
の実装は、操作に DataContractSerializerOperationBehavior
が登録されているかどうかをチェックすることにより、DataContract を使用する操作を検索します。登録されている場合は、その動作に DataContractSurrogate
プロパティが設定されます。この処理を行うサンプル コードを次に示します。この操作にサロゲートが設定されると、シリアル化および逆シリアル化のために動作でサロゲートが有効化されます。
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();
}
}
メタデータの生成中にサロゲートをプラグインとして使用するには、追加手順が必要です。これを行うための機構として、このサンプルで示す IWsdlExportExtension
が用意されています。さらに、WsdlExporter
を直接変更するという方法もあります。
AllowNonSerializableTypesAttribute
属性は IWsdlExportExtension
と IContractBehavior
を実装しています。この場合、拡張機能として IContractBehavior
または IEndpointBehavior
を使用できます。IWsdlExportExtension.ExportContract
メソッドの実装は、DataContract のスキーマ生成中に使用されるXsdDataContractExporter
にサロゲートを追加することによって、サロゲートを有効にします。これを行う方法を次のコード スニペットに示します。
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();
}
サンプルを実行すると、クライアントは AddEmployee の呼び出しに続いて、最初の呼び出しが正常に行われたかどうかをチェックする GetEmployee を呼び出します。GetEmployee の操作要求の結果は、クライアント コンソール ウィンドウに表示されます。GetEmployee 操作では、従業員の検索が正常に行われ、"found" と出力される必要があります。
![]() |
---|
このサンプルでは、シリアル化、逆シリアル化、およびメタデータの生成で、サロゲートをプラグインとして使用する方法を示します。メタデータからコードを生成するためにサロゲートをプラグインとして使用する方法を示すものではありません。クライアント コードの生成にプラグインとしてサロゲートを使用するサンプルについては、「カスタム WSDL パブリケーション」のサンプルを参照してください。 |
サンプルを設定、ビルド、および実行するには
「Windows Communication Foundation サンプルの 1 回限りのセットアップの手順」が実行済みであることを確認します。
ソリューションの C# 版をビルドするには、「Windows Communication Foundation サンプルのビルド」の手順に従います。
サンプルを単一コンピュータ構成または複数コンピュータ構成で実行するには、「Windows Communication Foundation サンプルの実行」の手順に従います。
Copyright © 2007 by Microsoft Corporation.All rights reserved.