具有多个名称空间的XML序列化 - 向后兼容性

时间:2012-02-20 08:57:11

标签: c# xml-serialization datacontractserializer

我有一个1.0版的应用程序,类似于:

class MyBaseDTO
{
   [XmlElementAttribute(DataType="base64Binary", IsNullable=true, ElementName="Data")]
   public byte[] Data{get;set}
}

和子类

class MySubDTO
{
    [XmlElementAttribute(DataType="base64Binary", IsNullable=true, ElementName="MoreData")]
    public byte[] MoreData{get;set}
}

现在版本1.1我想将MySubDTO.MoreData移动到MyBaseDTO。 问题是,当我使用1.1客户端与1.0服务器进行通信时,由于xml看起来像以下情况,因此不会对MoreData进行序列化:

<a:MyBaseDTO i:type="b:MySubDTO"><a:Data>...</a:Data><b:MoreData>...</b:MoreData></a:MyBaseDTO>

如果我添加

class MyBaseDTO
{
   [XmlElementAttribute(DataType="base64Binary", IsNullable=true, ElementName="Data")]
   public byte[] Data(){get;set}
   [XmlElementAttribute(DataType="base64Binary", IsNullable=true, ElementName="MoreData", NameSpace="MyBaseDTO")]
   public byte[] MoreData(){get;set}
}

它当然有效但我希望有可能理解MoreData可能有两个不同的命名空间。我正在使用WCF在Web服务之间进行通信,并使用DataContractSerializer来序列化服务器端的对象。这可以实现吗?

1 个答案:

答案 0 :(得分:0)

您有几个选择:

  • 我认为这是IExtensibleDataObject(扩展数据)的设计方案!我们的想法是,如果数据合同的v1使用扩展数据接口进行修饰,它将自动忽略,存储和往返数据合同的未来版本(包括未来未知类型)中的数据,而不会出现任何问题。

要为特定类型启用往返,您的类型应该是IExtensibleDataObject接口。该接口包含一个属性ExtensionData(返回ExtensionDataObject类型)。该属性存储当前版本未知的数据协定的未来版本中的任何数据。这是我的意思的一个例子:

[DataContract]
public class Person : IExtensibleDataObject
{
    [DataMember]
    public string fullName;
    private ExtensionDataObject theData;

    public virtual ExtensionDataObject ExtensionData
    {
        get { return theData; }
        set { theData = value; }
    }
}

当WCF基础结构遇到不属于原始数据协定的数据时,它会将数据存储并保留在此属性中。除临时存储外,它不以任何其他方式处理。如果将对象返回到其原始位置,则还会返回原始(未知)数据。

您可以随时关闭此往返功能,方法是在DataContractSerializer构造函数中将ignoreExtensionDataObject设置为true,或者在ServiceBehaviorAttribute上将IgnoreExtensionDataObject属性设置为true。它确实有性能损失,所以如果你不需要它,我会把它关掉。

  • 上述指南确实要求您切换到DataContractSerializer。如果您不能为此类型执行此操作,则可能必须使用IDataContractSurrogate将此XML类型转换为类似于您所执行操作的DataContract类型。还允许您基于每个类型或每个对象执行自定义JSON序列化和反序列化。