當某型別(非資料契約)與目標資料契約結構差異較大,需將其物件序列化為契約對應 XML,或從契約 XML 反序列化為該型別物件,資料契約代理(IDataContractSurrogate)提供了標準化解決方案。
範例場景: Contact(FullName、Sex)與 Customer 資料契約(FirstName、LastName、Gender)結構不同,需雙向轉換。
IDataContractSurrogate 關鍵三方法:
GetDataContractType(Type):型別替換(如 Contact → Customer)GetObjectToSerialize(object, Type):序列化前物件替換(Contact 實例 → Customer 實例)GetDeserializedObject(object, Type):反序列化後物件替換(Customer 實例 → Contact 實例)public class ContractSurrogate : IDataContractSurrogate
{
public Type GetDataContractType(Type type)
=> type == typeof(Contact) ? typeof(Customer) : type;
public object GetObjectToSerialize(object obj, Type targetType)
{
if (obj is Contact c)
return new Customer { FirstName = c.FullName.Split(' ')[0], LastName = c.FullName.Split(' ')[1], Gender = c.Sex };
return obj;
}
public object GetDeserializedObject(object obj, Type targetType)
{
if (obj is Customer c)
return new Contact { FullName = $"{c.FirstName} {c.LastName}", Sex = c.Gender };
return obj;
}
// 其他介面成員略...
}
建構 DataContractSerializer 時傳入 Surrogate:
var serializer = new DataContractSerializer(typeof(Contact), ..., surrogate);
結果: Contact{FullName="Bill Gates", Sex="Male"} 序列化輸出與 Customer 完全一致:
<Customer xmlns="https://www.artech.com"> <FirstName>Bill</FirstName> <LastName>Gates</LastName> <Gender>Male</Gender> </Customer>
反序列化還原的 Contact 與原物件 Equals 為 true。
foreach (var ep in host.Description.Endpoints)
foreach (var op in ep.Contract.Operations)
{
var behavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (behavior != null) behavior.DataContractSurrogate = new ContractSurrogate();
else op.Behaviors.Add(new DataContractSerializerOperationBehavior(op) { DataContractSurrogate = new ContractSurrogate() });
}
Surrogate 模式讓舊系統型別、第三方型別無缝接入 WCF 契約,無需修改原型別定義,是整合與遷移專案的利器。