天天看點

年前辭職-WCF入門(6)

 前言

昨天早上去醫院做入職體檢,被告知要預約,本以為是要排隊,我連視訊都準備好了。。。結果就回來了。下午去了新公司那邊找房子,2了,因為公司提供了班車清單,我既然就隻在班車所經過的幾個地方找,卻遺漏了公司附近這個重要的位址。最後找了一個“江景房”,上陽台就能看到錢塘江。價格和現在的比翻了一倍,累了,不想找了。

有朋友讓我把标題字首“年前辭職”4個字拿了,好吧,我承認,我就是靠這個吸引一部分眼球的。

第六集 WCF DataContract & DataMember (WCF的Data和DataMember)

這些天寫下來關于那個mex還是有點困惑,早上在stackoverflow上搜到一個回答,感覺寫得挺好的,在此拿出來分享一下。位址:http://stackoverflow.com/questions/21522493/what-was-the-difference-between-wsdl-mex-endpoint-in-wcf 。或許如果你有WebService的經驗,了解起來會更輕松一些。站在使用者的角度,我試着拿掉了endpoint有關mex的定義,以及注釋了behaviors節點,然後通路http://localhost:8080/ 頁面給了我這麼一個提示:

年前辭職-WCF入門(6)

還是回到了最初。

還有一點,stackoverflow回答中向我們傳遞了一個意思,關于WCF,就像他這麼用就行,因為,WCF本身還有更多的複雜有趣的東西等我們去開發實踐。

今天講第六集,這兩個是用來修飾需要序列化的實體類的特性,并且也會涉及到KnownType 看了之後覺得是一個很有用的特性。

首先,我們來實作一個EmployeeService,主要的作用是用來根據id查詢Employee,以及向資料庫插入Employee。下面開始介紹:

資料庫部分

年前辭職-WCF入門(6)

我們建立了一張表,叫Employee,左邊是表結構,右邊是内容,Id列沒有用自增。

然後建立了2個存儲過程,一個spGetEmployeeById,一個SaveEmployee

select * from Employee where Id= @id;      
insert into Employee (Id ,Name,Gender,DateOfBirth) values (@id ,@name,@gender,@dateOfBirth)      

其他定義部分的就寫出來了。

服務部分 

年前辭職-WCF入門(6)
年前辭職-WCF入門(6)
1     public class Employee
 2     {
 3         private int _id;
 4         private string _name;
 5         private bool _gender;
 6         private DateTime _dateOfBirth;
 7 
 8         public int Id
 9         {
10             get { return _id; }
11             set { this._id = value; }
12         }
13         public String Name
14         {
15             get { return _name; }
16             set { this._name = value; }
17         }
18         public bool Gender
19         {
20             get { return _gender; }
21             set { this._gender = value; }
22         }
23         public DateTime DateOfBirth
24         {
25             get { return _dateOfBirth; }
26             set { this._dateOfBirth = value; }
27         }
28     }      

View Code

上面是Employee 類的定義,有人可能會納悶,為什麼要額外定義個私有變量,C#這個人性化的語言不是隻要寫get;set就ok?開始我也有這個樣的疑惑。但其實,這裡是為了說明問題,特地這麼寫的。

年前辭職-WCF入門(6)
年前辭職-WCF入門(6)
public class EmployeeService : IEmployeeService
    {
        public Employee GetEmployee(int id)
        {
            Employee emp = null;
            var connStr = ConfigurationManager.ConnectionStrings["WCFEmployee"].ConnectionString;
            using(var conn = new SqlConnection(connStr)) {
                conn.Open();
                var cmd = conn.CreateCommand();
                cmd.CommandType = System.Data.CommandType.StoredProcedure;
                cmd.CommandText = "spGetEmployeeById";
                cmd.Parameters.Add(new SqlParameter("id", id));
                var reader = cmd.ExecuteReader();
                if(!reader.HasRows) return emp;
                emp = new Employee();
                while(reader.Read()) {
                    emp.Id = Convert.ToInt32(reader["Id"]);
                    emp.Name = reader["Name"].ToString();
                    emp.Gender = Convert.ToBoolean(reader["Gender"]);
                    emp.DateOfBirth = Convert.ToDateTime(reader["DateOfBirth"]);
                }
            }
            return emp;
        }

        public void SaveEmployee(Employee emp)
        {
            var connStr = ConfigurationManager.ConnectionStrings["WCFEmployee"].ConnectionString;
            using(var conn = new SqlConnection(connStr)) {
                conn.Open();
                var cmd = conn.CreateCommand();
                cmd.CommandType = System.Data.CommandType.StoredProcedure;
                cmd.CommandText = "spSaveEmployee";
                cmd.Parameters.Add(new SqlParameter("id", emp.Id));
                cmd.Parameters.Add(new SqlParameter("name", emp.Name));
                cmd.Parameters.Add(new SqlParameter("gender", emp.Gender));
                cmd.Parameters.Add(new SqlParameter("dateOfBirth", emp.DateOfBirth));
                cmd.ExecuteNonQuery();
            }
        }
    }      

上面是EmployeeService.cs 用了最基本的ADO.net操作。

再建一個控制台程式,來托管這個服務,運作成功。

用戶端調用

建立一個WebForm的用戶端,實作如下效果,代碼不貼了,都很基本。

年前辭職-WCF入門(6)

在id框裡面輸入id,查詢這個id的對應的資訊。

年前辭職-WCF入門(6)

沒有查到給提示。

年前辭職-WCF入門(6)

輸入資訊點儲存提示,儲存到資料庫。

寫完之後,一切運作順利。在介紹下面東西之前,我們先介紹幾個概念

  • 什麼是Serialization和Deserialization

從WCF角度來說,Serialization(序列化)是個轉換的過程,它把一個實體類轉換為XML,反過來講,通過XML檔案,得到一個實體類的過程叫Deserialization(反序列化)。

  • 序列化有什麼用

這裡有一篇 stackoverflow 上的問答,大緻意思是說用來存儲以及傳輸資料用的。and 序列化是必須的。

如果不特殊指定,WCF用DataContractSerializer來序列化object(終于出現标題上的關鍵字了)。

為了序列化Employee,我們可以用SerializableAttribute 或者 DataContractAttribute特性修飾這個類。但看看上面的Employee類,我們并沒有加上那兩個特性。那是因為,從framework 3.5開始,如果我們沒有使用DataContract 或者DataMember 特性,那麼WCF的DataContractSerializer會自動把所有的public屬性按照字典序的順序序列化。讓我們通路http://localhost:8080/?wsdl 來看看:

搜尋datacontract 

年前辭職-WCF入門(6)

 然後在位址欄裡面輸入後面的schemaLocation的值 http://localhost:8080/?xsd=xsd2 回車:

年前辭職-WCF入門(6)

Employee是一個complexType,下面的sequence裡面有他的四個屬性。這是預設生成的schema。

上面說了我們可以通過給一個類加Serializable或者是DataContract特性來顯式标記一個需要序列化的類,下面我們來看看這兩種方式有什麼不同。

先看用Serializable标記的:

年前辭職-WCF入門(6)

我們看到,所有帶下劃線的私有變量都被序列化了。

再看看用DataContract的效果:

年前辭職-WCF入門(6)

由于我們隻給類标記了DataContract特性,沒有任何字段被序列化了。。。(因為沒有序列化字段,用戶端在調用這個類的時候也是無法擷取到對應的屬性的。如圖:

年前辭職-WCF入門(6)

其實,DataContract應該是和DataMember配合使用。并且,這也是WCF推薦的做法。下面我們來實作一個。

在此之前,我們先看一下DataMember特性所包含的屬性:連結

年前辭職-WCF入門(6)

通過這些屬性,我們可以自由的控制他們在序列化時的名稱,順序等等。

年前辭職-WCF入門(6)
年前辭職-WCF入門(6)
1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Runtime.Serialization;
 5 using System.Text;
 6 
 7 namespace EmployeeService
 8 {
 9     [DataContract]
10     public class Employee
11     {
12         private int _id;
13         private string _name;
14         private bool _gender;
15         private DateTime _dateOfBirth;
16 
17         [DataMember(Order = 1)]
18         public int Id
19         {
20             get { return _id; }
21             set { this._id = value; }
22         }
23         [DataMember(Order = 2)]
24         public String Name
25         {
26             get { return _name; }
27             set { this._name = value; }
28         }
29         [DataMember(Order = 3)]
30         public bool Gender
31         {
32             get { return _gender; }
33             set { this._gender = value; }
34         }
35         [DataMember(Order = 4)]
36         public DateTime DateOfBirth
37         {
38             get { return _dateOfBirth; }
39             set { this._dateOfBirth = value; }
40         }
41     }
42 }      
年前辭職-WCF入門(6)

通過添加DataMember特性,字段回來了,并且序列化的順序也按照我的賦予的排好了。

總結一下,用DataContract 和 DataMember來控制我們需要序列化的對象。

下面還有KnowTypeAttribute的知識點,貌似有不少東西好寫,還是另開一篇吧。。。文章長了看的人就更少了。。。

Thank you!

wcf

繼續閱讀