序列化合约方法参数时如何自定义 WCF 使用的流程? [英] How to customize the process employed by WCF when serializing contract method arguments?
问题描述
我想制定一个人为的场景,但它有坚实的实际基础.想象一个集合类型 COuter,它是另一个集合类型 CInner 实例的包装器.两者都实现了 IList(不要介意 T).
I would like to formulate a contrived scenario, which nevertheless has firm actual basis. Imagine a collection type COuter, which is a wrapper around an instance of another collection type CInner. Both implement IList (never mind the T).
此外,一个 COuter 实例被埋在某个对象图中,其根(让我们将其称为 R)从 WCF 服务方法返回.
Furthermore, a COuter instance is buried inside some object graph, the root of which (let us refer to it as R) is returned from a WCF service method.
我的问题是如何自定义 WCF 序列化过程,以便在返回 R 时,序列化 COuter 实例的请求将通过我的代码进行路由,这将提取 CInner 并将其传递给序列化程序.因此接收端仍然得到R,只是在对象图中没有找到COuter实例.
My question is how can I customize the WCF serialization process, so that when R is returned, the request to serialize the COuter instance will be routed through my code, which will extract CInner and pass it to the serializer instead. Thus the receiving end still gets R, only no COuter instance is found in the object graph.
希望WCF如何序列化方法调用?将包含答案,不幸的是那里提到的文章 (http://msdn.microsoft.com/en-us/magazine/cc163569.aspx) 仅提及使用 IDataContractSurrogate 接口可以实现高级序列化方案,但未提供详细信息.另一方面,我真的很想看到一个有效的例子.
I hoped that How does WCF serialize the method call? will contain the answer, unfortunately the article mentioned there (http://msdn.microsoft.com/en-us/magazine/cc163569.aspx) only barely mentions that advanced serialization scenarios are possible using IDataContractSurrogate interface, but no details are given. I am, on the other hand, would really like to see a working example.
非常感谢您.
编辑
我创建了一个简单的 WCF 示例,它演示了这个问题.存档位于此处 - norellow"docs.google.com/leaf?id=0B2pbsdBJxJI3NzFiNjcxMmEtMTM5Yy00MWY2LWFiMTUtNjJiNjdkYTU1ZTk4&sort=name&layout=list&num=50
I have created a trivial WCF sample, which demonstrates the issue. The archive is located here - https://docs.google.com/leaf?id=0B2pbsdBJxJI3NzFiNjcxMmEtMTM5Yy00MWY2LWFiMTUtNjJiNjdkYTU1ZTk4&sort=name&layout=list&num=50
它包含三个小项目:
- HelloServiceAPI - 包含服务接口和参数类型
- Host - HelloService 主机
- 客户端 - 一个简单的控制台客户端.
服务定义了一个方法,该方法返回一个 HelloServiceResult
类型的实例,其中包含对 COuterList
类型的引用,该类型包装了 CInnerList
类型.引用被指定为IMyListInterface
,其中COuterList
和CInnerList
都实现了这个接口.我需要的是,当结果在传输到客户端之前被序列化时,COuterList
引用被替换为包装的 CInnerList
引用.我知道这可以通过利用 WCF 的现有功能来完成,我只是不知道如何.
The service defines one method, which returns an instance of the HelloServiceResult
type, which contains a reference to COuterList
type, which wraps CInnerList
type. The reference is specified as IMyListInterface
, where both COuterList
and CInnerList
implement this interface. What I need is that when the result is serialized before being transmitted to the client, the COuterList
reference be replaced with the wrapped CInnerList
reference. I know this can be done by utilizing the existing abilities of WCF, I just do not know how.
推荐答案
以下是您实现自己的代理的方法:
Here is how you implement your own Surrogate:
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
}
}
然后你创建一个自定义的序列化器操作行为:
Then you create a custom Serializer Operation Behavior :
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());
}
}
之后,您创建一个属性以将上述操作行为应用于操作合同:
After that, you create an attribute to apply the above operation behavior to an operation 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));
}
}
最后,您将此属性应用于操作:
And finally, you apply this Attribute to an operation :
[OperationContract]
[CustomDataContractFormat]
void DoWork();
如果您想将此应用于整个服务,那么您可以自定义服务行为而不是操作行为.
If you want to apply this to whole service, then you customize Service Behavior instead of Operation Behavior.
以下是用于创建此示例的参考资料:
Here are the references that were used to create this example :
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.idatacontractsurrogate.aspx
http:///social.msdn.microsoft.com/forums/en-US/wcf/thread/e4d55f3f-86d1-441d-9187-64fbd8ab2b3d/
这篇关于序列化合约方法参数时如何自定义 WCF 使用的流程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!