没有已知类型的 WCF 反序列化 [英] WCF deserialization without known types

查看:18
本文介绍了没有已知类型的 WCF 反序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

first, I hope I provide enough information to make things clear, if not please ask for more.

我有一个使用 Duplex Channel 和 OneWay 方法调用的有效 WCF 通信.ServiceHost 位于使用 NetPipeBinding 的托管 WPF 应用程序内,客户端位于该应用程序内的 AppDomain 中.只要所有类型都是原始类型(字符串、日期时间...)或指定为已知类型(ListList),一切都按预期工作).但是我需要发送其他类型,我无法为其添加已知类型属性,因为我在编译时不知道它们.

I have a working WCF communication using Duplex Channel and OneWay method calls. The ServiceHost is located inside a managed WPF application using NetPipeBinding, the client lives in a AppDomain inside that application. Everything is working as expected as long as all types are primitive (string, DateTime, ...) or specified as known type (List<object>, List<string>). But I need to send other types, for which I can´t add a known type attribute because I don´t know them at compile time.

正如我在这里读到的那样 (http://msdn.microsoft.com/library/ms731923(v=vs.100).aspx) 支持所有具有公共属性的公共类型,以及使用 SerializableAttribute 修饰的类型.

As I read here (http://msdn.microsoft.com/library/ms731923(v=vs.100).aspx) all public types with public properties are supported, and so are types decorated with SerializableAttribute.

我尝试转移一个非常简单的类:

I tried to transfer a very simple class:

public class ADT
{
  public string Name { get; set; }
}

作为第二次尝试

[Serializable]
public class SerializableADT
{
  public string Name { get; set; }
}

和 Herdo 的建议

and as suggested by Herdo

[DataContract]
public class DataContractADT
{
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public object Value { get; set; }
}

但是这三种类型的反序列化都失败了.

but the deserialization fails for all three types.

尝试序列化参数时出错_http://tempuri.org/:returnValue.InnerException 消息是类型带有数据协定名称的TestLibraries.SeriablizableADT"'SeriablizableADT:_http://schemas.datacontract.org/2004/07/TestLibraries'不是预期的.考虑使用 DataContractResolver 或添加任何已知类型列表中静态未知的类型 - 例如,通过使用KnownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表.'.请参见InnerException 了解更多详情.

There was an error while trying to serialize parameter _http://tempuri.org/:returnValue. The InnerException message was 'Type 'TestLibraries.SeriablizableADT' with data contract name 'SeriablizableADT:_http://schemas.datacontract.org/2004/07/TestLibraries' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.

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

How can I marshal any type that meets the MSDN rules (e.g. decorated with Serializable) without any compile time changes?

推荐答案

如果这是一个完全内部的服务,您可以切换到使用 NetDataContractSerializer,它通过包含完整类型和程序集来解决这个问题信息(注意此序列化程序完全破坏了互操作性和合同版本控制 - 因此切勿将其用于外部公开的服务).不需要 KnownType.要使用它,您需要一个行为和一个属性.您可以在合同或单个操作中放置以下属性:

If this is a completely internal service, you can switch to using the NetDataContractSerializer, which solves this problem by including full type and assembly information (note this serializer completely breaks interoperability and contract versioning - so never use it for externally-exposed services). No KnownType necessary. To use it, you need a behavior and an attribute. You can place the following attribute on your contract or on a single operation:

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

这篇关于没有已知类型的 WCF 反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆