wcf - 序列化合约方法参数时如何自定义 WCF 使用的流程?

标签 wcf serialization

我想制定一个人为的场景,但它有坚实的实际基础。想象一个集合类型 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

它包含三个小项目:

  • HelloServiceAPI - 包含服务接口(interface)和参数类型
  • 主机 - HelloService 主机
  • 客户端 - 一个简单的控制台客户端。

  • 该服务定义了一个方法,它返回 HelloServiceResult 的一个实例。类型,其中包含对 COuterList 的引用类型,包含 CInnerList类型。引用指定为 IMyListInterface , 其中两个 COuterListCInnerList实现这个接口(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/

    相关文章:

    c# - 使用客户端 Web 服务时出现内容错误

    java - Serializable/Cloneable/... 的惯用设计在 Scala 中看起来如何?

    c# - 如何在序列化 OData 响应时忽略 Null 值

    c# - 使用 Newtonsoft 进行预期 C# 时未引发异常

    java - 如何构建适合java客户端的WCF服务

    c# - 从不同的文件加载 wcf 主机配置

    c# - Schema First WCF Web 服务模型的优势?

    WCF 无法与权限建立 SSL/TLS 安全通道的信任关系

    python - 当使用 Dill 和与 Pickle 配合良好的代码时,出现 "pickle exhausted before end of frame"

    javascript - 响应式(Reactive)和动态表单字段