数据契约的定义与数据契约序列化器(3)
通过MaxItemsInObjectGraph限定序列化对象的数量
拒绝服务(DoS- Denial of Service)是一种常用的黑客攻击行为,黑客通过生成大容量的数据频繁地对服务器发送请求,最终导致服务器不堪重负而崩溃。对于WCF的序列化或反序列化来说,数据的容量越大、成员越多、层次越深,序列化的时间就越长,耗用的资源就越多,如果黑客频繁地发送一个海量的数组过来,那么服务就会因为忙于进行反序列化的工作而没有足够的资源处理正常的请求,从而导致瘫痪。
在这种情况下,可以通过MaxItemsInObjectGraph这个属性设置DataContractSerializer允许被序列化或反序列化对象的数量上限,一旦超过设定的这个上限,序列化或反序列化的工作将会立即中止,从而在一定程度上解决了通过发送大集合数据形式的拒绝服务攻击。DataContractSerializer中定义了以下3个重载的构造函数使我们能够设定MaxItemsInObjectGraph属性。
-
public
sealed class DataContractSerializer :
XmlObjectSerializer -
{
-
//其他成员 -
<Type>public DataContractSerializer(Type type,
IEnumerableknownTypes, -
int maxItemsInObjectGraph, bool
ignoreExtensionDataObject, bool -
preserveObjectReferences , IDataContractSurrogate
dataContractSurrogate); -
-
public DataContractSerializer(Type type, string
rootName,string -
<Type>rootNamespace, IEnumerable knownTypes,
intmaxItemsInObjectGraph, -
bool ignoreExtensionDataObjec t, bool
preserveObjectReferences, -
IDataContractSurrogate dataContractSurrogate); -
-
public DataContractSerializer(Type type,
XmlDictionaryStringrootName, -
<Type>XmlDictionaryString rootNamespace,
IEnumerableknownTypes, int -
maxItemsInObjectGraph, bool
ignoreExtensionDataObject, bool -
preserveObjectReferences , IDataContractSurrogate
dataContractSurrogate); -
-
public int MaxItemsInObjectGraph { get; } -
}
那么DataContractSerializer在进行具体的序列化时,对象的个数如何计算呢?经过我的实验,发现采用的计算规则是这样的:对象自身算一个对象,所有成员及所有内嵌的成员都算一个对象。我们通过一个具体的例子来证实这一点,在上面定义的泛型Serialize方法上加另一个参数maxItemsInObjectGraph,并调用另一个构造函数来创建DataContractSerializer对象。
-
public
static <T>(Tvoid Serialize instance,
stringfileName, int -
maxItemsInObjectGraph) -
{
-
serializerDataContractSerializer = new
DataContractSerializer(typeof(T), -
null,maxItemsInObjectGraph,false,false,null); -
writerusing (XmlWriter = new
XmlTextWriter(fileName,Encoding.UTF8)) -
{ -
serializer.WriteObject(writer, instance); -
} -
Process.Start(fileName); -
}
我们现在准备调用上面的方法对一个集合对象进行序列化,为此定义了一个OrderCollection的类型,它直接继承了List<Order>。
-
public
class <Order>OrderCollection : List -
{
} -
-
[DataContract]
-
public
class Order -
{
-
[DataMember] -
public Guid ID -
{ get; set; } -
-
[DataMember] -
public DateTime Date -
{ get; set; } -
-
[DataMember] -
public string Customer -
{ get; set; } -
-
[DataMember] -
public string ShipAddress -
{ get; set; } -
}
在下面的代码中,创建了OrderCollection对象,并添加了10个Order对象,如果该对象被序列化,最终被序列化对象数量是多少呢?应该这样来算,OrderCollection对象本身算一个,每一个Order对象自身也算一个,Order对象具有4个属性,各算一个,那么最终计算出来的个数是10×5+1=51个。但是在调用Serialize方法的时候,指定的上限仅仅是10×5=50。所以当调用DataContractSerializer的WriteObject方法时,会抛出如图5-2所示的SerializationException异常。如果maxItemsInObjectGraph设为51则一切正常。
-
OrderCollection
orders = newOrderCollection(); -
for
(int i= 0;i <10; i++) -
{
-
orderOrder = newOrder() -
{ -
ID= Guid.NewGuid(), -
Date= DateTime.Today, -
Customer= "NCS", -
ShipAddress= "#328, Airport Rd,
IndustrialPark, Suzhou JiangSu -
Province", -
}; -
orders.Add(order); -
}
-
Serialize(orders,
@"E:\order.xml", 10*5);
