【问题标题】:WCF deserialization without known types没有已知类型的 WCF 反序列化
【发布时间】:2014-03-31 14:35:35
【问题描述】:

首先,我希望我提供足够的信息来说明问题,如果没有,请询​​问更多。

我有一个使用双工通道和 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 消息是“类型 带有数据合同名称的“TestLibraries.SeriablizableADT” 'SeriablizableADT:_http://schemas.datacontract.org/2004/07/TestLibraries' 预计不会。考虑使用 DataContractResolver 或添加任何 已知类型列表中静态未知的类型 - 例如, 通过使用 KnownTypeAttribute 属性或将它们添加到 传递给 DataContractSerializer 的已知类型列表。请参见 InnerException 了解更多详情。

如何在不更改任何编译时间的情况下编组符合 MSDN 规则的任何类型(例如,用 Serializable 装饰)?

【问题讨论】:

  • 您是否尝试过 DataContractSerializeableADT 属性?
  • 是的,我做到了 - 但我得到了同样的错误。我读过只要使用默认的 DataContractSerializer,Serializable 和 DataContract 的行为就相同。我目前正在试验 DataContractResolver 方式(来自异常消息) - 但仍然没有运气。

标签: c# wcf serialization


【解决方案1】:

如果这是一个完全内部的服务,您可以切换到使用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);
    }
}

【讨论】:

  • 非常感谢 - 这就是我正在寻找的!
  • 伊莱,我怎么夸你都不够。您的实用程序类是救生员。谢谢你的洞察力。
【解决方案2】:

我在使用未知类型方面也失败了,所以我走上了一条丑陋的道路:对于编译时未知的类型,我手动序列化它们并通过 WCF 传输字节流。

编辑:查看 DataContractResolver 后,它看起来几乎相同: http://msdn.microsoft.com/de-de/library/dd807504(v=vs.110).aspx

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-17
    • 2011-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多