随笔 - 40  文章 - 0  评论 - 196 

写过WCF程序的朋友都知道,在对实体对象在WCF和客户端之间传递时一定要加DataContract标记这个类并用DataMember来标记要序列化的属性/字段。这一直正确,只是在.NET Framework 3.5 SP1中新添加了一些支持,那就是你不一定必须对这些实体对象应用DataContract标记,这被称作对plain old C# objects(POCO)的序列化支持。

 

Serializable标记大家都很熟悉,它是XmlSerializer的标记,在WCF中其实很少用这个标记,因为我们WCF用的是DataContractSerializer,对应的标记也是DataContract。但对于SP1来说,Serializable也以XmlSerializer的规则被正常解析,其对应的Mapping规则和Serializer对应,其公有可读写字段被默认序列化。当然,你也可以通过XmlElement等标记来做高级映射,但这不是我们这里需要谈及的内容。

 

DataContract对应的序列化处理叫做DataContactSerializer。在WCF中一旦一个类被标记为DataContract,那么只有标记为DataMember的字段/属性才会被序列化。但如果你使用DataContract标记,那么DataContractSerializer默认将所有公有可读写字段序列化(这和Serializable是一样的)。假设我们有这么一个类:

    public class Person

    {

        public Person()

        { }

 

        public Person(string strId, string strName)

        {

            this.Id = strId;

            this.Name = strName;

        }

 

        private string strid;

 

        public string Id { get { return strid; } set { strid = value; } }

        public string Name;

        public Person Spouse;

 

        private int Number = 343;

    }

 

对于DataSerializer来说,他和给所有公有属性添加DataMember并将类标记为DataContract是一样的。下面的一段程序分别将一个Person的实例对象分别用XmlSerializerDataContractSerializer来序列化:

        static void Main(string[] args)

        {

 

            Person p = new Person();

            p.Id = "123";

            p.Name = "Aaron";

            p.Spouse = new Person();

            p.Spouse.Id = "456";

            p.Spouse.Name = "Monica";

 

            DataContractSerializer dcs = new DataContractSerializer(typeof(Person));

            using (FileStream fs = new FileStream("person.xml", FileMode.Create))

            {

                dcs.WriteObject(fs, p);

            }

 

            XmlSerializer xs = new XmlSerializer(typeof(Person));

            using (FileStream fs = new FileStream("person_serialization.xml", FileMode.Create))

            {

                xs.Serialize(fs, p);

            }

        }

对于序列化后的内容我们得到的结果其实是一样的:仅有公有属性/字段被序列化

<Person xmlns="http://schemas.datacontract.org/2004/07/Serialization" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

                <Id>123</Id>

                <Name>Aaron</Name>

                <Spouse>

                                <Id>456</Id>

                                <Name>Monica</Name>

                                <Spouse i:nil="true"/>

                </Spouse>

</Person>

但如果你使用了DataContract来标记这个类,却没有使用DataMember,那么没有任何属性/字段被序列化:

    [DataContract]

    public class Person

    {

        private string strid;

 

        public string Id { get { return strid; } set { strid = value; } }

        public string Name;

        public Person Spouse;

 

        private int Number = 343;

    }

 

<Person xmlns="http://schemas.datacontract.org/2004/07/Serialization" xmlns:i=http://www.w3.org/2001/XMLSchema-instance />

 

对于将类标记成SerializableDataContractSerializer的序列化可能让我们觉得有些奇怪,它本质上是将所有可读写字段序列化,这其中还包括私有字段。例如我们将Person类用[Serializable]标记,执行程序,我们会得到以下的结果:

<Person xmlns="http://schemas.datacontract.org/2004/07/Serialization" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

                <Name>Aaron</Name>

                <Number>0</Number>

                <Spouse>

                                <Name>Monica</Name>

                                <Number>0</Number>

                                <Spouse i:nil="true"/>

                                <_id>456</_id>

                </Spouse>

                <_id>123</_id>

</Person>

一个简单的WCF程序来看看来检验一下是否正确。在Contract生命中我们并不需要制定任何的标记,并声明一个得到DeskMesh的方法:

    [ServiceContract]

    public interface IDeskMesh

    {

        [OperationContract]

        DeskMesh GetDeskMesh(string name);

    }

    public class DeskMesh

    {

        private int _id;

        private int Number = 4433;

 

        public int ID

        {

            get { return _id; }

            set { _id = value; }

        }

        public string Name { get; set; }

        public string Description { get; set; }

        public string Unit { get; set; }

        public float Price { get; set; }

        public DateTime Created { get; set; }

 

        public override string ToString()

        {

            return string.Format("ID:{4}"r"nName: {0}"r"nUnit:{1}"r"nPrice:{2}"r"nCreated:{3}"r"nNumber:{5}",

                Name, Unit, Price, Created.ToShortDateString(),ID.ToString(),Number.ToString());

        }

    }

 

客户端调用,会返回一个DeskMesh的实例。通过结果,你会发现这完全和你标记DataContract的实体在WCF两端传递一模一样。

       void Main(string[] args)

        {

            Console.WriteLine("Requesting...");

 

            ServiceClient client = new ServiceClient();

            DeskMesh mesh = client.GetDeskMesh("");

 

            Console.WriteLine(mesh.ToString());

            Console.WriteLine("press any key to continue...");

            Console.Read();

        }

 

总结一下吧,WCF中应用各个标记时所作的序列化处理:

1.          不给任何标记将会做XML映射,所有公有属性/字段都会被序列化

2.          [Serializable]标记会将所有可读写字段序列化

3.        [DataContract][DataMember]联合使用来标记被序列化的字段

 

Click here to get the sample WCF project

Tag标签: VS2008 WCF,C#
posted on 2008-11-22 11:06 Allan. 阅读(1227) 评论(7)  编辑 收藏 网摘

  回复  引用    
2008-11-22 11:51 | 惯例噢[未注册用户]
这部书
是指哪部书?

  回复  引用  查看    
2008-11-22 15:06 | G yc {Son of VB.NET}      
不过,这么些好像有点乱哦~~


  回复  引用  查看    
2008-11-22 20:01 | Steven Chen      
我想知道如果是
[DataContract,Serializable]
Class Persion......

这个会怎样

  回复  引用  查看    
2008-11-22 20:47 | Allan.      
如果觉得乱的话只需要看看示例就成了。原本没打算介绍什么,因为这根本不算技术,一个可以偷懒的小技巧而已吧。

--引用--------------------------------------------------
G yc {Son of VB.NET}: 不过,这么些好像有点乱哦~~


--------------------------------------------------------

  回复  引用  查看    
2008-11-22 20:48 | Allan.      
有示例代码,你可以试一下。
可以肯定的是,序列化出来什么都没有,因为你需要找DataMember

--引用--------------------------------------------------
Steven Chen: 我想知道如果是
[DataContract,Serializable]
Class Persion......

这个会怎样
--------------------------------------------------------

  回复  引用  查看    
2008-11-22 20:49 | Allan.      
不好意思,笔误。应该是“这不是我们要讨论的”

--引用--------------------------------------------------
惯例噢: 这部书
是指哪部书?
--------------------------------------------------------

  回复  引用    
2008-12-19 08:31 | colder[游客][未注册用户]
1. 不给任何标记将会做XML映射,所有公有属性/字段都会被序列化

如果真是这样, 理论上所有类都应该能够被序列化, 但事实并非如此.
问题出在哪里?

发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

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

0 1338850




相关文章:

相关链接: