2014-11-03 63 views
0

让我们有一个非常简单的例子:指示WCF反序列化类型T1为T2

[ServiceContract] 
public interface IMyService 
{ 
    [OperationContract] 
    T1 GetData(); 
} 

[DataContract] 
[KnownType(typeof(T2))] 
public class T1 
{ 
    [DataMember] 
    int Value { get; set; } 
} 

[DataContract] 
public class T2: T1 
{ } 

我需要能够发送T1,而是接受它作为T2在客户端(简单的原因:企业的快速转换对象为客户端只读类型;将服务器池对象转换为客户端非池化类型,如果需要,我可以进一步阐述)。

为了使它有点复杂 - 该数据类型的树来发送具有多种类型,例如:

[OperationContract] 
TBase GetData(); 

[DataContract] 
[KnownType(typeof(T1))] 
[KnownType(typeof(T2))] 
[KnownType(typeof(T3))] 
[KnownType(typeof(Tn))] 
public class TBase 
{ 
    [DataMember] 
    int Value { get; set; } 
} 

[DataContract] 
public class T1: TBase { } 

[DataContract] 
public class T2: TBase { } 

[DataContract] 
public class T3: TBase { } 

[DataContract] 
public class Tn: TBase { } 

,我需要的就是接收所有类型,与T1的例外,那必须是作为T2收到。

我测试了序列化/反序列化部分很容易与DataContractSerializer一起使用,但我找不到如何指示WCF使用不同的DataContractSerializer来反序列化T1。

EDIT1: 看起来这应该是可行的byderiving定制DataContractResolver和注射这两种(客户端 - 服务器)上的操作合同双方WCF。我得到了这个几乎工作 - 序列化 - 反序列化本身按预期工作,WCF仍然失败。我会尽力回答后,一旦我发现

回答

1

两个WCF扩展点:

  • DataContractResolver派生(如在自己的答复中提到) - 让你定义XML和其所需的.NET类型之间的新的匹配。 Read more here
  • 实现IDataContractSurrogate - 将一个.Net类型替换为另一个类型用于序列化目的。不涉及XML。 Read more here

它们都以类似的方式注入,通过DataContractSerializerOperationBehavior上的属性注入。

1

DataContractResolver似乎是有执行这些任务的原因 - 让我重写它:

public class MyResolver : DataContractResolver 
{ 
    private XmlDictionaryString _typeName; 
    private XmlDictionaryString _typeNamespace; 

    public PooledPricesResolver() 
    { 
     XmlDictionary dictionary = new XmlDictionary(); 
     _typeName = dictionary.Add("T2"); 
     _typeNamespace = dictionary.Add("MyNamespace"); 
    } 

    public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace) 
    { 
     if (declaredType == typeof(T1)) 
     { 
      typeName = _typeName; //null; 
      typeNamespace = _typeNamespace; //null 
      return true; 
     } 

     return knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace); 
    } 

    public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver) 
    { 
     if (typeName == "T2" && typeNamespace == "MyNamespace") 
     { 
      return typeof(T1); 
     } 

     return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) ?? declaredType; 
    } 
} 

注意,这可能是更加复杂。或者,如果您需要将类型解析为基本类型,则还需要更高的性能 - 然后TryResolveType可以将typeName和名称空间初始化为空值,并且ResolveName可以只调用knownTypeResolver实现。

要注入服务器端(主机),这个解析器,你可以做到以下几点:

//_serviceHost is ServiceHost.ServiceHost type 
ContractDescription cd = _serviceHost.Description.Endpoints[0].Contract; 

//the string is the name of operation for which you can do the custom (de)serialization 
cd.Operations.Find("GetData") 

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

serializerBehavior.DataContractResolver = new MyResolver(); 

//Now you can start listening by _serviceHost.Open() 

在客户端,如果你用手工制作代理,您可以执行以下操作:

public class MyServiceProxy : System.ServiceModel.DuplexClientBase<IMyService>, IMyService 
{ 
    public MyServiceProxy(InstanceContext callbackInstance, Binding binding, EndpointAddress remoteAddress) 
     : base(callbackInstance, binding, remoteAddress) 
    { 
     ContractDescription cd = this.Endpoint.Contract; 

     //the string is the name of operation for which you can do the custom (de)serialization 
     cd.Operations.Find("GetData") 

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

     serializerBehavior.DataContractResolver = new MyResolver(); 
    } 

    ... 

} 

客户端现在可以根据您的需求接收反序列化的类型。

浮现在脑海
相关问题