序列化合约方法参数时如何自定义 WCF 使用的流程? [英] How to customize the process employed by WCF when serializing contract method arguments?

查看:29
本文介绍了序列化合约方法参数时如何自定义 WCF 使用的流程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想制定一个人为的场景,但它有坚实的实际基础.想象一个集合类型 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,其中COuterListCInnerList 都实现了这个接口.我需要的是,当结果在传输到客户端之前被序列化时,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://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 使用的流程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆