代码之家  ›  专栏  ›  技术社区  ›  mark

在序列化约定方法参数时,如何自定义WCF使用的过程?

  •  4
  • mark  · 技术社区  · 15 年前

    我想制定一个做作的方案,尽管有坚实的实际基础。设想一个集合类型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接口可以实现高级序列化场景,但没有给出详细信息。另一方面,我很想看到一个有效的例子。

    提前非常感谢。

    编辑

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

    它包含三个小项目:

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

    服务定义了一个方法,该方法返回 HelloServiceResult 类型,其中包含对 COuterList 类型,包装 CInnerList 类型。引用被指定为 IMyListInterface ,其中 会议员名单 辛纳列表 实现这个接口。我需要的是,当结果在传输到客户机之前被序列化时, 会议员名单 引用被换行 辛纳列表 参考。我知道这可以通过利用现有的WCF能力来实现,我只是不知道怎么做。

    2 回复  |  直到 14 年前
        1
  •  8
  •   decyclone    15 年前

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

    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());
        }
    }
    

    之后,您将创建一个属性来将上述操作行为应用于操作协定:

    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/

        2
  •  0
  •   decyclone    15 年前

    你试过老好人吗 OnSerializingAttribute ?

    [Serializable]
    [KnownType(typeof(COuterList))]
    public class HelloServiceResult
    {
        public IMyListInterface List;
    
        [OnSerialized]
        void OnSerializing(StreamingContext context)
        {
            if (List is COuterList)
            {
                List = ((List as COuterList).InnerList as CInnerList);
            }
        }
    }