IExtensibleDataObject,MSDN给出的解释为:提供一个数据结构,用于存储 XmlObjectSerializer 在反序列化一个用 DataContractAttribute 属性标记的类型期间遇到的额外数据。命名空间: System.Runtime.Serialization,程序集: System.Runtime.Serialization。
IExtensibleDataObject 接口提供了单个属性,该属性设置或返回一个用于存储数据协定外部数据的结构。额外数据存储在 ExtensionDataObject 类的实例中,并且通过 ExtensionData 属性访问。在接收、处理和返回数据的往返操作中,额外数据被原封不动地返回到原始发送方。这可用于存储从协定的将来版本接收的数据。如果您没有实现该接口,则会在往返操作中忽略和丢弃任何额外数据。
在WCF契约版本管理过程中,可以借用此接口,使传输的数据契约类继承此接口。IExtensibleDataObject对客户端的影响:在1.0版本的客户端上保存从2.0版本的服务端所获得的数据;确保在更新时能够包含原始的数据。对服务端的影响:保存从客户端获得的未知数据;用于支持其他调用了2.0版本的服务但仍需要1.0版本的服务进行实际处理的情况;会承担拒绝服务攻击和非必要的使用服务器资源的风险。
IExtensibleDataObject主要是通过序列化方式与反序列化方式对WCF数据契约起作用:在序列化数据契约的时候,保存未知的元素;在反序列化的时候,多余的数据将被放入到一个字典中;在序列化过程中,相同的数据按照其原始提供的样子以XML的形式写入。
下面我们通过一个DEMO来演示IExtensibleDataObject对数据契约的变化产生的影响:
1、新建一个Console Application程序,删除自动添加的文件;
2、新建Item.cs类,代码如下:
[DataContract(Name = "Item", Namespace = "http://schemas.xinhaijulan.com/demos/IExtensibleDataObjectApp")]
public class Item : IExtensibleDataObject
{
[DataMember]
public string Name { get; set; }
public ExtensionDataObject ExtensionData { get; set; }
}
3、新建ItemV2.cs类,代码如下:
[DataContract(Name = "Item", Namespace = "http://schemas.xinhaijulan.com/demos/IExtensibleDataObjectApp")]
public class ItemV2 : IExtensibleDataObject
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
public ExtensionDataObject ExtensionData { get; set; }
}
注意:Item.cs与ItemV2.cs都继承且实现了IExtensibleDataObject接口。
4、新建ItemNo.cs与ItemV2No.cs类,这2个类并没有实现IExtensibleDataObject接口,代码如下:
[DataContract(Name = "Item", Namespace = "http://schemas.xinhaijulan.com/demos/IExtensibleDataObjectApp")]
public class ItemNo
{
[DataMember]
public string Name { get; set; }
}
[DataContract(Name = "Item", Namespace = "http://schemas.xinhaijulan.com/demos/IExtensibleDataObjectApp")]
public class ItemV2No
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
}
5、在Program类中新建方法SerializingItemV2、SerializingItem与DeserializeItemV2方法,这三个方法为对实现了IExtensibleDataObject数据契约类进行序列化与反序列化,代码如下:
static void SerializingItemV2(string path)
{
ItemV2 itemV2 = new ItemV2();
itemV2.Name = "Name";
itemV2.Id = 88;
DataContractSerializer ser =
new DataContractSerializer(typeof(ItemV2));
FileStream fs = new FileStream(path, FileMode.Create);
ser.WriteObject(fs, itemV2);
fs.Close();
Console.WriteLine("Serializing ItemV2" + Environment.NewLine + "Id:{0}" + Environment.NewLine + "Name:{1}", itemV2.Id, itemV2.Name);
}
static void SerializingItem(string path)
{
DataContractSerializer ser =
new DataContractSerializer(typeof(Item));
FileStream fs = new FileStream(path, FileMode.Open);
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
Item item = ser.ReadObject(reader, false) as Item;
fs.Close();
Console.WriteLine("Deserialize to Item" + Environment.NewLine + "Old Name:{0}", item.Name);
item.Name = "NewName";
fs = new FileStream(path, FileMode.Create);
ser.WriteObject(fs, item);
fs.Close();
Console.WriteLine("Serializing Item" + Environment.NewLine + "New Name:{0}", item.Name);
}
static void DeserializeItemV2(string path)
{
FileStream fs = new FileStream(path, FileMode.Open);
DataContractSerializer ser = new DataContractSerializer(typeof(ItemV2));
ItemV2 itemV2 = ser.ReadObject(fs) as ItemV2;
fs.Close();
Console.WriteLine("Deserialize to ItemV2" + Environment.NewLine + "Id:{0}" + Environment.NewLine + "Name:{1}", itemV2.Id, itemV2.Name);
}
6、在Program类中新建方法SerializingItemV2No、SerializingItemNo与DeserializeItemV2No方法,这三个方法为对没有实现了IExtensibleDataObject数据契约类进行序列化与反序列化,代码如下:
static void SerializingItemV2No(string path)
{
ItemV2No itemV2 = new ItemV2No();
itemV2.Name = "Name";
itemV2.Id = 88;
DataContractSerializer ser =
new DataContractSerializer(typeof(ItemV2No));
FileStream fs = new FileStream(path, FileMode.Create);
ser.WriteObject(fs, itemV2);
fs.Close();
Console.WriteLine("Serializing ItemV2" + Environment.NewLine + "Id:{0}" + Environment.NewLine + "Name:{1}", itemV2.Id, itemV2.Name);
}
static void SerializingItemNo(string path)
{
DataContractSerializer ser =
new DataContractSerializer(typeof(ItemNo));
FileStream fs = new FileStream(path, FileMode.Open);
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
ItemNo item = ser.ReadObject(reader, false) as ItemNo;
fs.Close();
Console.WriteLine("Deserialize to Item" + Environment.NewLine + "Old Name:{0}", item.Name);
item.Name = "NewName";
fs = new FileStream(path, FileMode.Create);
ser.WriteObject(fs, item);
fs.Close();
Console.WriteLine("Serializing Item" + Environment.NewLine + "New Name:{0}", item.Name);
}
static void DeserializeItemV2No(string path)
{
FileStream fs = new FileStream(path, FileMode.Open);
DataContractSerializer ser = new DataContractSerializer(typeof(ItemV2No));
ItemV2No itemV2 = (ItemV2No)ser.ReadObject(fs);
fs.Close();
Console.WriteLine("Deserialize to ItemV2" + Environment.NewLine + "Id:{0}" + Environment.NewLine + "Name:{1}", itemV2.Id, itemV2.Name);
}
7、在Main方法中添加代码,如下:
static void Main(string[] args)
{
try
{
Console.WriteLine("----------Use IExtensibleDataObject Begin----------");
Console.WriteLine();
SerializingItemV2("v2.xml");
Console.WriteLine();
SerializingItem("v2.xml");
Console.WriteLine();
DeserializeItemV2("v2.xml");
Console.WriteLine("Id value saved.");
Console.WriteLine();
Console.WriteLine("----------Use IExtensibleDataObject End----------" + Environment.NewLine);
Console.WriteLine("----------UnUse IExtensibleDataObject Begin----------");
Console.WriteLine();
SerializingItemV2No("v2No.xml");
Console.WriteLine();
SerializingItemNo("v2No.xml");
Console.WriteLine();
DeserializeItemV2No("v2No.xml");
Console.WriteLine("Id value lose.");
Console.WriteLine();
Console.WriteLine("----------UnUse IExtensibleDataObject Begin----------");
}
catch (SerializationException ex)
{
Console.WriteLine("{0}: {1}", ex.Message, ex.StackTrace);
}
Console.ReadLine();
}
8、运行此项目,可以看到如下输出:
----------Use IExtensibleDataObject Begin----------
Serializing ItemV2
Id:88
Name:Name
Deserialize to Item
Old Name:Name
Serializing Item
New Name:NewName
Deserialize to ItemV2
Id:88
Name:NewName
Id value saved.
----------Use IExtensibleDataObject End----------
----------UnUse IExtensibleDataObject Begin----------
Serializing ItemV2
Id:88
Name:Name
Deserialize to Item
Old Name:Name
Serializing Item
New Name:NewName
Deserialize to ItemV2
Id:0
Name:NewName
Id value lose.
----------UnUse IExtensibleDataObject Begin----------
从以上输出我们可以看到,在使用了IExtensibleDataObject的序列化与反序列化过程中,数据并没有丢失,而在没有使用了IExtensibleDataObject的序列化与反序列化的过程中,数据有所丢失。
虽然IExtensibleDataObject给WCF的版本更新带来一定的兼容性,但也带来一定的风险与资源浪费,然而我们可以通过配置或代码方式关闭此特性。
配置方式:
<serviceBehaviors>
<behavior name="serviceBehavior">
<dataContractSerializer ignoreExtensionDataObject="true"/>
</behavior>
</serviceBehaviors>
代码方式:
[ServiceBehavior(IgnoreExtensionDataObject=true)]
public class ExplicitService : IExplicitService
{
}
至此,WCF契约版本管理—IExtensibleDataObject介绍完毕。
作者:心海巨澜
出处:http://xinhaijulan.cnblogs.com
版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。