一步一个脚印学习WCF系列之WCF契约设计—3-复杂类型序列化之数据契约DataContractAttribute

  阅读目录

  一:DataContractAttribute 

  二:DataMemberAttribute

  三:实例

  一:DataContractAttribute

    . 在schema和CRL类型之间转换

      在WCF当中我们推荐的一种序列化方式是使用数据契约的这种方式,使用数据契约的方式和一般的序列化的方式是种类似的方式,也是在我们需要进行序列化的数据上面加DataContract特性,在加完DataContract特性以后,.NET本身会为我们实现schema也就是XSD和CRL类型之间的转换

    . 总是要提供命名空间

    . 能够提供显式的Name

      我们希望对Book这个类所表示的对象来进行序列化的话,我们可以在它上面加上DataContract特性,并且指明说在SOAP消息当中以什么名字来传递它,在这里是SOAP消息当中我们以BookInfo名称来传递它

1 [DataContract(Name="BookInfo",Namespace="http://schemas.menglin.net")]
2 public class Book
3 {
4 }

   二:DataMemberAttribute

    如果我们使用数据契约来描述的类,只有我们显式的把这个类当中的具体的成员通过DataMember来标记了,才表明这个成员是要参与到序列化当中,如果某一个成员没有使用DataMember来标记,表明这个成员不需要参与到序列化当中

    . 应用于域和属性

      -应用于域

               我们希望_name这个数据参与到序列化当中,或者说把它添加到SOAP数据包中,我们可以用DataMember特性来标记这个私有字段,且通过Name特性来明确_name在SOAP数据包中是使用什么名称的,也就是它使用什么具体名称存放于SOAP当中

1 [DataMember(Name = "BookName", IsRequired = false, Order = 0)]
2 private string _name;

      -应用于属性

        我们希望Name这个数据参与到序列化当中,或者说把它添加到SOAP数据包中,我们可以用DataMember特性来标记这个属性,且通过Name特性来明确Name在SOAP数据包中是使用什么名称的,也就是它使用什么具体名称存放于SOAP当中

 1 private string _name;
 2 /// <summary>
 3 /// 书本名称
 4 /// </summary>
 5 [DataMember(Name="BookName", IsRequired = false,Order = 0)]
 6 public string Name
 7 {
 8     get { return _name; }
 9     set { _name = value; }
10 }

    . 可以指定排列顺序

      我们要进行序列化的对象它在SOAP数据包中进行排序的位置,也就是它排在第几号,在这里Name在序列化的时候在SOAP数据包中排在第一位,如果我们没有指定Order的话,默认按字母排序

 1 private string _name;
 2 /// <summary>
 3 /// 书本名称
 4 /// </summary>
 5 [DataMember(Name="BookName", IsRequired = true,Order = 0)]
 6 public string Name
 7 {
 8       get { return _name; }
 9       set { _name = value; }
10 }

     . 能够显式的指定Name和IsRequired

      -Name

        通过Name特性来明确_name在SOAP数据包中是使用什么名称的,也就是它使用什么具体名称存放于SOAP当中

      -IsRequired

        这个属性Name是不是可为空的,也就是说在序列化之前是否必须要被赋值,IsRequired=true,表示Name在序列化之前必须要被赋值

 1 private string _name;
 2 /// <summary>
 3 /// 书本名称
 4 /// </summary>
 5 [DataMember(Name="BookName", IsRequired = true,Order = 0)]
 6 public string Name
 7 {
 8       get { return _name; }
 9       set { _name = value; }
10 }

   三:实例

    使用数据契约进行描述时,在WCF当中我们推荐的方式是对属性进行DataMember的描述,而不是通过字段进行描述,主要体现在OO的设计风格,对于类当中的成员,我们需要屏蔽掉外部的访问,也就是对于外部的对象而言,它只能访问这个类当中的属性,而不是直接去访问这个类当中的字段

    我们定义了一个Book类,并且指定了它的名称“Book_DataContract”,然后我们对这个类当中的属性进行了DataMember的描述,指明了它的名称,和在序列化之前是否要赋值的,以及在序列化的时候所排序的位置

    1:Book.cs 数据契约的定义

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Runtime.Serialization;
 6 
 7 namespace DataContract.Service
 8 {
 9     [DataContract(Name = "Book_DataContract", Namespace = "http://schames.menglin.net/2012/05/08")]
10     public class Book
11     {
12         private int _id;
13         /// <summary>
14         /// 书本ID
15         /// </summary>
16         [DataMember(Name = "ID_DataMember", IsRequired = false, Order = 0)]
17         public int ID
18         {
19             get { return _id; }
20             set { _id = value; }
21         }
22 
23         private string _name;
24         /// <summary>
25         /// 书本名称
26         /// </summary>
27         [DataMember(Name = "Name_DataMember", IsRequired = false, Order = 1)]
28         public string Name
29         {
30             get { return _name; }
31             set { _name = value; }
32         }
33         private string _author;
34         /// <summary>
35         /// 作者
36         /// </summary>
37         [DataMember(Name = "Author_DataMember", IsRequired = false, Order = 2)]
38         public string Author
39         {
40             get { return _author; }
41             set { _author = value; }
42         }
43       
44         private string _publisher;
45         /// <summary>
46         /// 出版商
47         /// </summary>
48         [DataMember(Name = "Publisher_DataMember", IsRequired = false, Order = 3)]
49         public string Publisher
50         {
51             get { return _publisher; }
52             set { _publisher = value; }
53         }
54 
55         private string _unit;
56         /// <summary>
57         /// 单位
58         /// </summary>
59         [DataMember(Name = "Unit_DataMember", IsRequired = false, Order = 4)]
60         public string Unit
61         {
62             get { return _unit; }
63             set { _unit = value; }
64         }
65 
66         private string _price;
67         /// <summary>
68         /// 价格
69         /// </summary>
70         [DataMember(Name = "Price_DataMember", IsRequired = false, Order = 5)]
71         public string Price
72         {
73             get { return _price; }
74             set { _price = value; }
75         }
76 
77         private string _addtime;
78         /// <summary>
79         /// 入库时间
80         /// </summary>
81         [DataMember(Name = "AddtTime_DataMember", IsRequired = false, Order = 6)]
82         public string AddtTime
83         {
84             get { return _addtime; }
85             set { _addtime = value; }
86         }
87     }
88 }

    2:IBookService.cs 服务契约的定义

      IBookService使用了Book,IBookService.cs是我们在Host或者在Server这一端为客户端所提供的服务,在这个服务里面我们主要为客户端提供了一个叫作“GetMyBook()”,一个叫作“SaveMyBook()”这么两个方法,这两个方法使用了Book对象,对于这个类而言的话,我们使用了IBookService这个接口来进行描述,同样我们指定了服务契约的名称和这个服务契约里面具体操作的名称

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.ServiceModel;
 6 
 7 using DataContract.Model;
 8 
 9 namespace DataContract.Service
10 {
11     [ServiceContract(Name = "Book_ServiceContract", Namespace = "http://schames.menglin.net/2012/05/08")]
12     public interface IBookService
13     {
14         [OperationContract(Name = "GetBook", Action = "http://schames.menglin.net/2012/05/08")]
15         Book GetMyBook();
16 
17         [OperationContract(Name = "SaveBook", Action = "http://schames.menglin.net/2012/05/09")]
18         void SaveMyBook(Book book);
19     }
20 
21     public class BookService : IBookService
22     {
23         private Book _book;
24         public Book GetMyBook()
25         {
26             return _book;
27         }
28 
29         public void SaveMyBook(Book book)
30         {
31             _book = book;
32         }
33     }
34 }

    3:Program.cs 服务宿主

      在Host这一端就是把BookService这个服务加载到Host当中

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.ServiceModel;
 6 
 7 using DataContract.Service;
 8 
 9 namespace Host
10 {
11     class Program
12     {
13         static void Main(string[] args)
14         {
15             using (ServiceHost host = new ServiceHost(typeof(BookService)))
16             {
17                 host.Open();
18                 Console.ReadLine();
19             }
20         }
21     }
22 }

     4:App.config 服务的配置

      IMetadataExchange这个接口的作用是用于对外提供服务的元数据,所谓元数据,大家可以理解为”描述数据的数据“,什么叫作“描述数据的数据”,比如:我们现在希望Host对外提供BookService这个服务,这个服务里面包含了若干个方法,以及这些方法有一些参数,这些方法的名称,这些参数的名称,以及Book里面具体的属性都是什么,以及它具体的类型,以及它排序的方式,我们把这些数据称为元数据,我们添加IMetadataExchange这个接口就是为了对外暴露元数据,我们为什么要对外暴露元数据呢?主要原因在于对于客户端而言它为了能够访问服务器端的服务的话,它必须要获得这些元数据,也就是它必须要获得服务器这一端服务的名称,方法的名称,以及具体数据的定义,这些定义如何来获得呢?就是通过IMetadataExchange这种方式来获得这些数据,因此在这里我们需要对外暴露出IMetadata这种交换的信息,使得客户端和服务器端之间能够互通

1 <endpoint address="mex"
2           binding="mexHttpBinding"
3           contract="IMetadataExchange"  />

 

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3     <system.serviceModel>
 4         <behaviors>
 5             <serviceBehaviors>
 6                 <behavior name="serviceBehavior">
 7                     <serviceMetadata httpGetEnabled="true" />
 8                 </behavior>
 9             </serviceBehaviors>
10         </behaviors>
11         <services>
12             <service name="DataContract.Service.BookService" behaviorConfiguration="serviceBehavior">
13                 <endpoint address="BookService"
14                           binding="netTcpBinding"
15                           contract="DataContract.Service.IBookService" />
16                 <endpoint address="mex"
17                           binding="mexHttpBinding"
18                           contract="IMetadataExchange"  />
19                 <host>
20                     <baseAddresses>
21                         <add baseAddress="http://localhost:8000"/>
22                         <add baseAddress="net.tcp://localhost:9000"/>
23                     </baseAddresses>
24                 </host>
25             </service>
26         </services>
27     </system.serviceModel>
28 </configuration>

  5:Form1.cs 客户端

    在这个实例中提供了一个Winform,在这个Winform里面有两个Button,一个叫做“得到书”,一个叫做“保存书”

   

  启动Host

  

  打开服务

  

 

posted @ 2012-07-22 18:05  David.Meng  阅读(4486)  评论(0编辑  收藏  举报