我想制定一个人为的场景,但它有坚实的实际基础。想象一个集合类型 COuter,它是另一个集合类型 CInner 的实例的包装器。两者都实现了 IList(不要介意 T)。
此外,COuter 实例隐藏在某个对象图中,其根(让我们将其称为 R)是从 WCF 服务方法返回的。
我的问题是如何自定义 WCF 序列化过程,以便在返回 R 时,序列化 COuter 实例的请求将通过我的代码进行路由,该代码将提取 CInner 并将其传递给序列化程序。因此接收端仍然得到 R,只是在对象图中没有找到 COuter 实例。
我希望 How does WCF serialize the method call?将包含答案,不幸的是那里提到的文章 (http://msdn.microsoft.com/en-us/magazine/cc163569.aspx) 只几乎没有提到使用 IDataContractSurrogate 接口(interface)可以实现高级序列化场景,但没有给出详细信息。另一方面,我真的很想看到一个可行的例子。
非常感谢您提前。
编辑
我创建了一个简单的 WCF 示例,它演示了这个问题。文件位于此处 - https://docs.google.com/leaf?id=0B2pbsdBJxJI3NzFiNjcxMmEtMTM5Yy00MWY2LWFiMTUtNjJiNjdkYTU1ZTk4&sort=name&layout=list&num=50
它包含三个小项目:
该服务定义了一个方法,它返回
HelloServiceResult
的一个实例。类型,其中包含对 COuterList
的引用类型,包含 CInnerList
类型。引用指定为 IMyListInterface
, 其中两个 COuterList
和 CInnerList
实现这个接口(interface)。我需要的是,当结果在传输到客户端之前被序列化时,COuterList
引用被替换为包裹的CInnerList
引用。我知道这可以通过利用 WCF 的现有能力来完成,我只是不知道如何。
最佳答案
以下是您如何实现自己的代理:
class YourCustomTypeSurrogate : IDataContractSurrogate
{
public Type GetDataContractType(Type type)
{
// Just for reference
//if (typeof(OldType).IsAssignableFrom(type))
//{
// return typeof(NewType);
//}
return type;
}
public object GetObjectToSerialize(object obj, Type targetType)
{
// This method is called on serialization.
//if (obj is OldType)
//{
// // ... use the XmlSerializer to perform the actual serialization.
// NewType newObj = new NewType();
// return newObj;
//}
return obj;
}
public object GetDeserializedObject(object obj, Type targetType)
{
// This method is called on deserialization.
// If PersonSurrogated is being deserialized...
//if (obj is NewType)
//{
// OldType newObj = new OldType();
// return newObj;
//}
return obj;
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
// This method is called on schema import.
//if (typeNamespace.Equals("Your Type Namespace"))
//{
// if (typeName.Equals("NewType"))
// {
// return typeof(OldType);
// }
//}
return null;
}
public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
{
// Not used in this sample.
// You could use this method to construct an entirely
// new CLR type when a certain type is imported, or modify a generated
// type in some way.
return typeDeclaration;
}
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
// Not used in this sample
return null;
}
public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
{
// Not used in this sample
return null;
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
{
// Not used in this sample
}
}
然后你创建一个自定义的序列化器操作行为:
public class CustomDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
public CustomDataContractSerializerOperationBehavior(OperationDescription operationDescription) : base(operationDescription) { }
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new DataContractSerializer(
type /*typeof OldType*/,
knownTypes,
int.MaxValue /*maxItemsInObjectGraph */,
false /*ignoreExtensionDataObject*/,
true /*preserveObjectReferences*/,
new YourCustomTypeSurrogate());
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(
type /*typeof OldType*/,
knownTypes,
int.MaxValue /*maxItemsInObjectGraph */,
false /*ignoreExtensionDataObject*/,
true /*preserveObjectReferences*/,
new YourCustomTypeSurrogate());
}
}
之后,您创建一个属性以将上述操作行为应用于操作契约(Contract):
public class CustomDataContractFormatAttribute : Attribute, IOperationBehavior
{
public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
{
}
public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
ReplaceDataContractSerializerOperationBehavior(description);
}
public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
{
ReplaceDataContractSerializerOperationBehavior(description);
}
public void Validate(OperationDescription description)
{
}
private static void ReplaceDataContractSerializerOperationBehavior(OperationDescription description)
{
DataContractSerializerOperationBehavior dcs = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcs != null)
description.Behaviors.Remove(dcs);
description.Behaviors.Add(new CustomDataContractSerializerOperationBehavior(description));
}
}
最后,将此属性应用于操作:
[OperationContract]
[CustomDataContractFormat]
void DoWork();
如果要将其应用于整个服务,则自定义服务行为而不是操作行为。
以下是用于创建此示例的引用:
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.idatacontractsurrogate.aspx
http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/
http://www.danrigsby.com/blog/index.php/2008/04/10/specifying-a-different-serializer-per-endpoint-in-wcf/
http://social.msdn.microsoft.com/forums/en-US/wcf/thread/e4d55f3f-86d1-441d-9187-64fbd8ab2b3d/
关于wcf - 序列化合约方法参数时如何自定义 WCF 使用的流程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3030969/