如何在合同指定接口时将派生对象作为基础对象进行传输

时间:2013-04-12 09:42:33

标签: wcf datacontract

如果[ServiceContract] [OperationContract]指定作为接口的返回值(IInterface),那么我可以返回一个Base对象(Base : IInterface)或一个Derived对象(Derived : Base)在服务器接口上使用ServerKnownType属性。

但是,如果我需要将Derived对象作为Base对象传输(因为Derived添加了服务器端功能,我不需要客户端),那么我卡住了。
派生类技巧[DataContract(Name = "Base")](参见here)在这种情况下(服务器方法返回接口)不起作用,因为我们必须将Derived对象和Base对象声明为KnownTypes - 和当服务器来解析要序列化的类型时,它不喜欢具有相同数据协定名称的2种不同的已知类型 - 并且在解析时将抛出异常。
如何在这种情况下转发派生为基地?

1 个答案:

答案 0 :(得分:0)

您可以使用以下DataContractResolver将[DataContract(Name =“Base”)]的使用扩展为Derived上的属性,以指定它应序列化为Base,以便在服务器接口方法返回接口而不是混凝土基础类型。
要使用它,必须将Base声明为KnownType(ServerKnownType),并且Derived必须具有[DataContract(Name =“Base”)]属性,但不能声明为KnownType。

    public class DeserializeAsBaseResolver : DataContractResolver {
        public static void Install(ServiceHost serviceHost) {

            SetSerializationBehavior(serviceHost, "MethodReturningIInterfac");
        }

        public static void SetSerializationBehavior(ServiceHost serviceHost, string contractMethodName) {
            ContractDescription cd = serviceHost.Description.Endpoints[0].Contract;
            OperationDescription myOperationDescription = cd.Operations.Find(contractMethodName);

            bool methodFound = (myOperationDescription != null);
            if (!methodFound) {
                string msg = string.Format("\"{0}\" not a valid method on {1}",
                                           contractMethodName, cd.ConfigurationName);
                throw new ArgumentException(msg);
            }

            DataContractSerializerOperationBehavior serializerBehavior =
                myOperationDescription.Behaviors.Find<DataContractSerializerOperationBehavior>();
            if (serializerBehavior == null) {
                serializerBehavior = new DataContractSerializerOperationBehavior(myOperationDescription);
                myOperationDescription.Behaviors.Add(serializerBehavior);
            }
            serializerBehavior.DataContractResolver = new DeserializeAsBaseResolver();
        }

        public override bool TryResolveType(Type type, Type declaredType,
                                            DataContractResolver knownTypeResolver,
                                            out XmlDictionaryString typeName,
                                            out XmlDictionaryString typeNamespace) {
            // Look for [DataContract(Name = "ClassType")] attribute and serialize as that
            // type if one is found:
            Type typeToResolveOn = type;
            DataContractAttribute dca = null;
            // .Net 4.0 and below code:
            object[] attributes = type.GetCustomAttributes(typeof(DataContractAttribute), false);
            foreach (object attibute in attributes) {
                if (attibute is DataContractAttribute) {
                    dca = attibute as DataContractAttribute;
                    break;
                }
            }
            // .Net 4.5 and above code:
            //dca = type.GetCustomAttribute<DataContractAttribute>();

            if (dca != null && !string.IsNullOrEmpty(dca.Name)) {
                string modifiedAssemblyQualifiedName = string.Format("{0}.{1}, {2}", type.Namespace, dca.Name, type.Assembly);
                Type serializeAsType = Type.GetType(modifiedAssemblyQualifiedName);
                if (serializeAsType != null)
                    typeToResolveOn = serializeAsType;
            }

            bool ret = knownTypeResolver.TryResolveType(typeToResolveOn, declaredType, null, out typeName, out typeNamespace);
            if (!ret && type != typeToResolveOn)
                ret = knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace);
            return ret;
        }

        public override Type ResolveName(string typeName, string typeNamespace,
                                         Type declaredType, DataContractResolver knownTypeResolver) {
            return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) ?? declaredType;
        }
    }

}