Artech

Develop every application as an art using the most suitable technologies!

常用链接

统计

积分与排名

网上邻居

我的博文系列

最新评论

[原创]我的WCF之旅(4):WCF中的序列化(Serialization)- Part II

... ...续Part I([原创] 我的WCF之旅(4):WCF中的序列化(Serialization)- Part I)

XMLSerializer

提到XMLSerializer,我想绝大多数人都知道这是asmx采用的Serializer。首先我们还是来看一个例子,通过比较Managed Type的结构和生成的XML的结构来总结这种序列化方式采用的是怎样的一种Mapping方式。和DataContractSerialzer Sample一样,我们要定义用于序列化对象所属的Type——XMLOrder和XMLProduct,他们和相面对应的DataContractOrder和DataContractProduct具有相同的成员。

using System;
using System.Collections.Generic;
using System.Text;

namespace Artech.WCFSerialization
{
    
public class XMLProduct
    
{
        
Private Fields

}



using System;
using System.Collections.Generic;
using System.Text;

namespace Artech.WCFSerialization
{
    
public class XMLOrder
    
{
        
private Guid _orderID;
        
private DateTime _orderDate;
        
private XMLProduct _product;
        
private int _quantity;

        
Constructors

        
Properties

        
public override string ToString()
        
{
            
return string.Format("ID: {0}\nDate:{1}\nProduct:\n\tID:{2}\n\tName:{3}\n\tProducing Area:{4}\n\tPrice:{5}\nQuantity:{6}",
                
this._orderID,this._orderDate,this._product.ProductID,this._product.ProductName,this._product.ProducingArea,this._product.UnitPrice,this._quantity);
        }

    }

}

编写Serialization的Code.

调用上面定义的方法,生成序列化的XML。

<?xml version="1.0" encoding="utf-8"?>
<XMLOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    
<OrderID>b695fd18-9cd7-4792-968a-0c0c3a3962c2</OrderID>
    
<OrderDate>2007-03-09T00:00:00+08:00</OrderDate>
    
<Product>
        
<ProductID>23a2fe03-d0a0-4ce5-b213-c7e5196af566</ProductID>
        
<ProductName>Dell PC</ProductName>
        
<UnitPrice>4500</UnitPrice>
    
</Product>
    
<Quantity>300</Quantity>
</XMLOrder>

这里我们总结出以下的Mapping关系:

  1. Root Element被指定为类名。
  2. 不会再Root Element中添加相应的Namaspace。
  3. 对象成员以XML Element的形式输出。
  4. 对象成员出现的顺利和在Type定义的顺序一致。
  5. 只有Public Field和可读可写得Proppery才会被序列化到XML中——比如定义在XMLProduct中的internal string ProducingArea没有出现在XML中。
  6. Type定义的时候不需要运用任何Attribute。

以上这些都是默认的Mapping关系,同DataContractSerializer一样,我们可以通过在Type以及它的成员中运用一些Attribute来改这种默认的Mapping。

  1. Root Element名称之后能为类名。
  2. 可以在Type上运用XMLRoot,通过Namaspace参数在Root Element指定Namespace。
  3. 可以通过在类成员上运用XMLElement Attribute和XMLAttribute Attribute指定对象成员转化成XMLElement还是XMLAttribute。并且可以通过NameSpace参数定义Namespace。
  4. 可以在XMLElement或者XMLAttribute Attribute 通过Order参数指定成员在XML出现的位置。
  5. 可以通过XmlIgnore attribute阻止对象成员被序列化。

基于上面这些,我们重新定义了XMLProduct和XMLOrder。

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

namespace Artech.WCFSerialization
{
    
public class XMLProduct
    
{
        
Private Fields

        
Constructors

        
Properties

    }

}


using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

namespace Artech.WCFSerialization
{
    [XmlRoot(Namespace 
= "http://artech.wcfSerialization/Samples/Order")]
    
public class XMLOrder
    
{
        
private Guid _orderID;
        
private DateTime _orderDate;
        
private XMLProduct _product;
        
private int _quantity;

        
Constructors

        
Properties

        
public override string ToString()
        
{
            
return string.Format("ID: {0}\nDate:{1}\nProduct:\n\tID:{2}\n\tName:{3}\n\tProducing Area:{4}\n\tPrice:{5}\nQuantity:{6}",
                
this._orderID,this._orderDate,this._product.ProductID,this._product.ProductName,this._product.ProducingArea,this._product.UnitPrice,this._quantity);
        }

    }

}

 

重新进行一次Serialization。我们可以得到下面的XML。

<?xml version="1.0" encoding="utf-8"?>
<XMLOrder id="9a0bbda4-1743-4398-bc4f-ee216e02695b" xmlns="http://artech.wcfSerialization/Samples/Order" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  
<product id="4e3aabe5-3a51-4000-9fd8-d821d164572a" xmlns="Http://Artech.WCFSerialization/Samples/Product">
    
<name>Dell PC</name>
    
<producingArea>Xiamen FuJian</producingArea>
    
<price>4500</price>
  
</product>
  
<quantity>300</quantity>
  
<date>2007-03-09T00:00:00+08:00</date>
</XMLOrder>

分析完XMLSerializer的Serialization功能,我们照例来分析它的反向过程—Deserialization。下面的Deserialization的Code。

调用DeserializeViaXMLSerializer,得到下面的Screen Shot。下面显示的Order对象的信息和我们利用DataContractSerializaer进行Deserialization是的输出没有什么两样。不过有趣的是上面多出了两行额外的输出:The constructor of XMLProduct has been invocated! The constructor of XMLOrder has been invocated。而这个操作实际上是定义在XMLProduct和XMLOrder的默认(无参)构造函数里的。所此我们可以得出这样的结论——用XMLSerializer进程Deserialization,会调用的默认(无参)构造函数来初始化对象。 

DataContractSerializer V.S. XMLSerializer

上面我们分别分析了两种不同的Serializer,现在我们来简单总结一下他们的区别:

特性

XMLSerializer

DataContractSerializer

默认Mapping

所有Public Field和可读可写Property

所有DataMember Filed、Property

是否需要Attribute

不需要

DataContract DataMember或者Serializable

成员的默认次序

Type中定义的顺序

字母排序

兼容性

.asmx

Remoting

Deserialzation

调用默认构造函数

不会调用



WCF相关内容:
[原创]我的WCF之旅(1):创建一个简单的WCF程序
[原创]我的WCF之旅(2):Endpoint Overview
[原创]我的WCF之旅(3):在WCF中实现双向通信(Bi-directional Communication)
[原创]我的WCF之旅(4):WCF中的序列化(Serialization)- Part I
[原创]我的WCF之旅(4):WCF中的序列化(Serialization)- Part II
[原创]我的WCF之旅(5):Service Contract中的重载(Overloading)
[原创]我的WCF之旅(6):在Winform Application中调用Duplex Service出现TimeoutException的原因和解决方案
[原创]我的WCF之旅(7):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的继承
[原创]我的WCF之旅(8):WCF中的Session和Instancing Management
[原创]我的WCF之旅(9):如何在WCF中使用tcpTrace来进行Soap Trace
[原创]我的WCF之旅(10): 如何在WCF进行Exception Handling
[原创]我的WCF之旅(11):再谈WCF的双向通讯-基于Http的双向通讯 V.S. 基于TCP的双向通讯

[原创]我的WCF之旅(12):使用MSMQ进行Reliable Messaging
[原创]我的WCF之旅(13):创建基于MSMQ的Responsive Service

posted on 2007-03-10 18:04 Artech 阅读(6838) 评论(33)  编辑 收藏 网摘

评论

#1楼[楼主] 2007-03-10 18:06 Artech      

由于文章(加上code)过长,严重影响Load的速度,故拆分成两部分。   回复  引用  查看    

#2楼 2007-03-12 08:17 webabcd      

支持 收藏了   回复  引用  查看    

#3楼 2007-03-17 10:47 qy1141      

很好,一口气看完了你的五篇文章,受益匪浅,严重感谢!   回复  引用  查看    

#4楼[楼主] 2007-03-17 12:10 Artech      

@qy1141
谢谢你的关注。
  回复  引用  查看    

#5楼 2007-06-15 11:16 妖居      

如果不在Attribute里面加入Namespace的话,Deserializer就会失败,是不是因为无法找到Namespace造成的呢?
而且XMLSerializer无法序列化非公有属性,就会使得一些私有的属性没有被正确的反序列化出来。可能会导致数据的丢失啊。
但是DataSerializer全部序列化所有的数据,也有可能出现内部数据外泄的危险。怎么解决呢?我是想能不能把一些重要的Private数据Encrypt之后再序列化呢?
呵呵,瞎想,瞎想…… :p
  回复  引用  查看    

#6楼[楼主] 2007-06-15 11:26 Artech      

@妖居
XML中的Namespace必须要和你的Class定义相匹配才能实现反序列化。
  回复  引用  查看    

#7楼[楼主] 2007-06-15 11:34 Artech      

@妖居
XMLSerializer造成数据的丢失时在所难免的,不过我们对于交互的数据,一般般仅仅是对数据的封装,很少有相关处理逻辑。而只有Public的成员是可以被访问的,使用对Private实现序列化也没有什么必要。
至于DataContract Serializer,我们标记了DataMemberAttribute就以为着我们需要对该成员实现序列化,如果没有标记DataMemberAttribute则不会进行序列化。
  回复  引用  查看    

#8楼 2007-06-15 11:50 妖居      

我只是有这么个想法,毕竟我还没有做过真正的分布式应用,没有什么经验。   回复  引用  查看    

#9楼 2007-07-15 19:44 江南白衣      

请问博主为什么实现IPrincipal的类型数据无法在WCF中序列化呢,在Remoting和WebService中是没问题的,比如说我传递一个GernericPricipal类型的参数给服务端,确报无法序列化的错误,琢磨了好几次,都搞不清楚。   回复  引用  查看    

#10楼 2007-07-15 21:48 江南白衣      

已经解决,在 [ServiceContract]下面加上
[ServiceKnownType(typeof(GenericPrincipal))]
[ServiceKnownType(typeof(GenericIdentity))]
:)
  回复  引用  查看    

#11楼[楼主] 2007-07-15 21:58 Artech      

@江南白衣
呵呵,正在看GenericPrincipal的定义呢,还以为GenericPrincipal有什么特殊的。
  回复  引用  查看    

#12楼 2008-02-26 13:58 千年之夏[未注册用户]

正在拜读中   回复  引用    

#13楼 2008-03-18 15:12 伊凡1983[未注册用户]

感谢,学习中。。。。。   回复  引用    

#14楼 2008-06-22 21:33 cc@      

序列化后的类型实例可以在客户端和服务器端直接传递吗?传递时需要显示反序列化什么的吗?   回复  引用  查看    

#15楼[楼主] 2008-06-26 12:08 Artech      

@cc@
序列化的目的就是为了是对象能在client/server传递。
  回复  引用  查看    

#16楼 2008-07-20 18:59 问候[未注册用户]

编写Serialization的Code下面的序列化代码看不到,那个+号打不开.
到了:下面的Deserialization的Code。又是一样的.
这样,刚好讲序列化和反序列化的代码都看不到,太关键了.还有我的WCF之旅(3):中也有类似情况.晕啊!!!好在(3)中有代码可下载.这个就没了.
  回复  引用    

#17楼[楼主] 2008-07-24 09:17 Artech      

@问候
是打不开,我找找是否还有Source Code
  回复  引用  查看    

#18楼 2008-07-31 16:54 rax[未注册用户]

请问为什么我不能返回List<object>我这里的实体类不确定,所以我需要返回object,我是准备通过配置读取实体类的,搞了好久,不知道怎么办,烦请协助,谢谢~~
[OperationContract]
public List<object> RetrieveData(string filter, object[] parameters)
{
ITable table = GetEntityTable();
IEnumerable<object> source = string.IsNullOrEmpty(filter) ? table.Cast<object>() : table.Where(filter, parameters).Cast<object>();
return new List<object>(source);
}
  回复  引用    

#19楼[楼主] 2008-07-31 17:38 Artech      

@rax
因为WCF需要序列化,必须知道“具体”的类型,List<object>,对于object, WCF根本就不知道具体是什么类型,所以无法序列化,换成具体的类型。
  回复  引用  查看    

#20楼 2008-10-10 14:59 airwolf2026      

@17楼的代码
就是那个无法打开"+"号的代码
static void DeserializeViaXMLSerializer()
{
string fileName = _basePath + "Order.XmlSerializer.xml";
XMLOrder order;
using (FileStream fs = new FileStream(fileName, FileMode.Open))
{
XmlSerializer serializer = new XmlSerializer(typeof(XMLOrder));
using (XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas()))
{
order = serializer.Deserialize(reader) as XMLOrder;
}
}
Console.WriteLine(order);
Console.Read();
}

其实这个都已经加载进来了,用工具把那个"+"所在位置的html source提取出来,就看得到源码了.
  回复  引用  查看    

#21楼[楼主] 2008-10-14 10:08 Artech      

@airwolf2026
谢谢!
  回复  引用  查看    

#22楼 2008-11-10 15:13 狗狗[未注册用户]

现在有一个客户端程序(WinForm)和服务器程序,之间通过WCF通讯,客户端获取服务器的相关数据,在客户端编辑后保存,服务器保存和获取数据的方式是采用xml序列化,现在的问题是,如何保证我客户端编辑的数据被正确序列化到服务器的xml文件中去了, 谢谢   回复  引用    

#23楼[楼主] 2008-11-11 17:08 Artech      

@狗狗
“保证我客户端编辑的数据被正确序列化到服务器的xml文件中”这句不是很明明白!
  回复  引用  查看    

#24楼 2008-12-22 16:14 学习wcf中[未注册用户]

请问,为什么序列化时要使用XmlDictionaryWriter来封装FileStream,使用serializer.Serialize(writer,order), 而不直接使用serializer.Serialize(fs,order);   回复  引用    

#25楼[楼主] 2008-12-26 09:42 Artech      

@学习wcf中
在真正WCF执行过程中,XmlDictionaryWriter和XmlDictionaryReader实现了消息的编码和读写, DataContractSerializer和XmlSerializer实现序列化!
  回复  引用  查看    

#26楼 2009-01-05 15:59 学习wcf中[未注册用户]

请问,WCF中的序列化应该怎么去传递,我的client端在request service时,传递数据,我想序列化后,传递过去,可是该怎么做,不是很明白
还有是不是序列化都应该在service端,而反序列化都应该在client端?

btw,楼主的MSN方便留给我吗
谢谢
  回复  引用    

#27楼[楼主] 2009-01-06 09:11 Artech      


--引用--------------------------------------------------
学习wcf中: 请问,WCF中的序列化应该怎么去传递,我的client端在request service时,传递数据,我想序列化后,传递过去,可是该怎么做,不是很明白
还有是不是序列化都应该在service端,而反序列化都应该在client端?

btw,楼主的MSN方便留给我吗
谢谢
--------------------------------------------------------
WCF序列化的本质就是将序列化参数生成Message对象,不需要你手工做。
序列化和反序列化同时发生在Client和Server。
Client:Input parameters-〉Request Message(Serialization);Reply Message -〉Return Value(or ref/out parameter) (Deserialization)
Server:与之相反!
  回复  引用  查看    

#28楼 2009-02-05 15:11 飞翔的小猪[未注册用户]

半年前看你的WCF系列毫无头绪,一点也看不懂,现在再来看,却恍然大悟,一切看来都很明了,看来半年前的确很菜,非常感谢.   回复  引用    

#29楼 2009-02-27 15:55 王文斌      

我一个VS2005的项目,直接转到VS2008中,以前通过WSE3.0来配置的WebService,转到2008后创建WebService实例的时候报错,例如:UploadMgrSlaveWse oWse = new UploadMgrSlaveWse(); 不能找到UploadMgrSlaveWse 这个命名空间,我想请问下这个问题怎么解决?VS2008好像不用WSE了?   回复  引用  查看    

#30楼[楼主] 2009-03-02 16:10 Artech      

@王文斌
对WSE不时很熟;)
  回复  引用  查看    




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 670446




相关文章:

相关链接: