本文介绍了对多个程序集使用自定义 DataContractResolver的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 MEF 应用程序中有以下设置:

I have following setup in a MEF application:

组装MyBaseAssembly:

namespace My.Namespace
{
    [DataContract]
    public class Container
    {
        [DataMember]
        public Data Item { get; set; }
    }

    [DataContract]
    public class Data
    {
        [DataMember]
        public string Foo { get; set; }
    }
}

Assembly SecondAssembly,引用MyBaseAssembly:

Assembly SecondAssembly, references the MyBaseAssembly:

namespace My.Another.Namespace
{
    [DataContract]
    public class SecondData : Data
    {
        [DataMember]
        public string Bar { get; set; }
    }
}

在我的应用程序内部的某个地方,我创建了一个 Container 对象:

Somewhere deep inside of my application I create a Container object:

Container container = new Container();
container.Item = new SecondData { Bar = "test" };

我想序列化和反序列化 container 对象.由于 SecondAssembly 是一个 MEF 模块,我需要动态检测和解析数据契约中的类型,所以 KnownTypeAttribute 不是一个好的解决方案.

I want to serialize and de-serialize the container object. Since the SecondAssembly is a MEF-module, I need to dynamically detect and resolve the types in the data contract, so the KnownTypeAttribute is not a good solution.

我创建了一个自定义的DataContractResolver,但我不知道如何获取用于反序列化的程序集信息.

I created a custom DataContractResolver, but I don't know how do I get the assembly information for de-serialization.

在序列化时,我得到以下 XML:

On serialization, I get following XML:

<d4p1:SecondData
    xmlns:d6p1="http://schemas.datacontract.org/2004/07/My.Another.Namespace"
    i:type="d7p1:My.Another.Namespace.SecondData">
...
</d4p1:SecondData>

这是默认的DataContract序列化行为:我们得到了类型名称和类型命名空间,但是没有(显式的)程序集信息!

This is the default DataContract serialization behavior: we get the type name and the type namespace, but there is no (explicit) assembly information!

尝试反序列化此 XML,我无法确定使用哪个程序集来解析类型:

Trying to de-serialize this XML, I cannot determine which assembly to use for resolving the type:

class SerializationTypeResolver : DataContractResolver
{
    ...

    public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
    {
        Type result = knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null);
        if (result == null)
        {
            // Here, I cannot rely on the declaredType parameter,
            // because it contains the declared type which is Data from MyBaseAssembly.
            // But I need the SecondData from the SecondAssembly!

            string assemblyName = ???; // How do I get this assembly name?
            string fullTypeName = typeName + ", " + assemblyName;
            result = Type.GetType(fullTypeName);
        }

        return result;
    }
}

所以我的问题是:在序列化和反序列化 DataContract 的同时存储和获取程序集名称的好方法是什么?

So my question is: what is the good way to store and get assembly name while serializing and de-serializing the DataContracts?

推荐答案

为什么在序列化时不使用 AssemblyQualifiedName?像这样:

Why not use AssemblyQualifiedName already when serializing? Like this:

internal class SerializationTypeResolver : DataContractResolver {
    public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace) {
        // not necessary to hardcode some type name of course, you can use some broader condition
        // like if type belongs to another assembly
        if (type.Name == "SecondData") {
            XmlDictionary dictionary = new XmlDictionary();
            // use assembly qualified name
            typeName = dictionary.Add(type.AssemblyQualifiedName);
            typeNamespace = dictionary.Add("http://tempuri.org"); // some namespace, does not really matter in this case
            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 (typeNamespace == "http://tempuri.org") {
            return Type.GetType(typeName); // assembly qualified already
        }
        return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null);
    }
}

这篇关于对多个程序集使用自定义 DataContractResolver的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 10:34