首先,我希望我提供足够的信息以使事情变得清晰,如果没有请求更多。
我使用Duplex Channel和OneWay方法调用进行有效的WCF通信。 ServiceHost位于使用NetPipeBinding的托管WPF应用程序内,客户端位于该应用程序内的AppDomain中。只要所有类型都是原始类型(字符串,日期时间,...)或指定为已知类型(List<object>
,List<string>
),一切都按预期工作。但是我需要发送其他类型,我不能添加已知的类型属性,因为我在编译时不知道它们。
正如我在这里阅读(http://msdn.microsoft.com/library/ms731923(v=vs.100).aspx)所有支持公共属性的公共类型都是受支持的,使用SerializableAttribute修饰的类型也是如此。
我试图转移一个非常简单的类:
public class ADT
{
public string Name { get; set; }
}
并作为第二次尝试
[Serializable]
public class SerializableADT
{
public string Name { get; set; }
}
并按照Herdo的建议
[DataContract]
public class DataContractADT
{
[DataMember]
public string Name { get; set; }
[DataMember]
public object Value { get; set; }
}
但所有三种类型的反序列化都失败了。
尝试序列化参数时出错 _http://tempuri.org/:的returnValue。 InnerException消息是'Type 带有数据协定名称的'TestLibraries.SeriablizableADT' 'SeriablizableADT:_http://schemas.datacontract.org/2004/07/TestLibraries' 不是预期的。考虑使用DataContractResolver或添加任何 静态地知道已知类型列表的类型 - 例如, 通过使用KnownTypeAttribute属性或将它们添加到 传递给DataContractSerializer的已知类型列表。'。请参阅 InnerException以获取更多详细信息。
如何在没有任何编译时间更改的情况下编组符合MSDN规则的任何类型(例如,使用Serializable修饰)?
答案 0 :(得分:2)
如果这是一个完全内部的服务,您可以切换到使用NetDataContractSerializer
,它通过包含完整的类型和汇编信息解决了这个问题(注意这个序列化器完全打破了互操作性和合同版本控制 - 所以永远不要将它用于外部公开的服务)。不需要KnownType
。要使用它,您需要一个行为和一个属性。您可以在合同或单个操作中放置以下属性:
public class UseNetDataContractSerializerAttribute : Attribute, IOperationBehavior, IContractBehavior
{
void IOperationBehavior.ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
ReplaceDataContractSerializerOperationBehavior(description);
}
void IOperationBehavior.ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
{
ReplaceDataContractSerializerOperationBehavior(description);
}
void IOperationBehavior.Validate(OperationDescription description)
{
}
void IOperationBehavior.AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
{
}
private static void ReplaceDataContractSerializerOperationBehavior(OperationDescription description)
{
var behavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (behavior != null)
{
description.Behaviors.Remove(behavior);
description.Behaviors.Add(new NetDataContractSerializerOperationBehavior(description));
}
}
void IContractBehavior.ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
foreach (var operation in contractDescription.Operations)
{
ReplaceDataContractSerializerOperationBehavior(operation);
}
}
void IContractBehavior.ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
foreach (var operation in contractDescription.Operations)
{
ReplaceDataContractSerializerOperationBehavior(operation);
}
}
void IContractBehavior.Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
}
void IContractBehavior.AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
}
public class NetDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
public NetDataContractSerializerOperationBehavior(OperationDescription operation)
: base(operation)
{
}
public NetDataContractSerializerOperationBehavior(OperationDescription operation, DataContractFormatAttribute dataContractFormatAttribute)
: base(operation, dataContractFormatAttribute)
{
}
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new NetDataContractSerializer(name, ns);
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new NetDataContractSerializer(name, ns);
}
}
答案 1 :(得分:0)
我也未能使用未知类型,因此我走了一条丑陋的路径:对于编译时未知的类型,我手动序列化它们并通过WCF传输字节流。
编辑:在查看DataContractResolver后,它看起来几乎相同: http://msdn.microsoft.com/de-de/library/dd807504(v=vs.110).aspx