如何在序列化合同方法参数时自定义WCF使用的进程?

mar*_*ark 4 wcf serialization

我想制定一个人为的设想,但它具有坚实的实际基础.想象一个集合类型COuter,它是另一个集合类型CInner的实例的包装器.两者都实现了IList(更别提了T).

此外,COuter实例被隐藏在一些对象图中,其根(我们将其称为R)从WCF服务方法返回.

我的问题是如何自定义WCF序列化过程,以便在返回R时,序列化COuter实例的请求将通过我的代码进行路由,这将提取CInner并将其传递给序列化器.因此,接收端仍然获得R,在对象图中只找不到COuter实例.

我希望WCF如何序列化方法调用?将包含答案,遗憾的是,那里提到的文章(http://msdn.microsoft.com/en-us/magazine/cc163569.aspx)几乎没有提到使用IDataContractSurrogate接口可以实现高级序列化方案,但没有给出详细信息.另一方面,我真的很想看到一个有效的例子.

非常感谢你提前.

编辑

我创建了一个简单的WCF示例,它演示了这个问题.该档案位于此处 - https://docs.google.com/leaf?id=0B2pbsdBJxJI3NzFiNjcxMmEtMTM5Yy00MWY2LWFiMTUtNjJiNjdkYTU1ZTk4&sort=name&layout=list&num=50

它包含三个小项目:

  • HelloServiceAPI - 包含服务接口和参数类型
  • 主机 - HelloService主机
  • 客户端 - 简单的控制台客户端.

该服务定义了一个方法,该方法返回一个HelloServiceResult类型的实例,该实例包含对COuterList包装CInnerList类型的类型的引用.参考被指定为IMyListInterface,其中两个COuterListCInnerList实现该接口.我需要的是,当结果在传输到客户端之前被序列化时,COuterList引用将被包装CInnerList引用替换.我知道这可以通过利用WCF的现有功能来完成,我只是不知道如何.

dec*_*one 8

以下是如何实现自己的代理:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您创建自定义序列化程序操作行为:

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

之后,创建一个属性以将上述操作行为应用于操作合同:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,将此属性应用于操作:

    [OperationContract]
    [CustomDataContractFormat]
    void DoWork();
Run Code Online (Sandbox Code Playgroud)

如果要将此应用于整个服务,则可以自定义"服务行为"而不是"操作行为".

以下是用于创建此示例的引用:

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/