WCF(二) Contract


上篇只是介紹了WCF的概述。具體的設置全是使用默認,這當然不可能滿足我們開發的需要。如果仔細理一理的話,你會發現WCF里面的設置其實不算多的(與SharePoint比較的話)。從這篇開始,我們一點一點來展開學習。這次先提最最常用的Contract。

Contract有人翻譯為:協定,契約。

WCF中有四種contract: 分別是:1.Service Contract. 2.Data Contract. 3. Fault Contract. 4.Message Contract.

還拿上篇中的例子(其實就是有Visual Studio2010替我們默認生成的代碼了)說事:

1.Service Contract共分為兩個部分:定義部分和實現部分。

 1     [ServiceContract]
 2     public interface IService1
 3     {
 4         [OperationContract]
 5         string GetData(int value);
 6 
 7         [OperationContract]
 8         CompositeType GetDataUsingDataContract(CompositeType composite);
 9       
10     }

這里IService就是一個service contract的定義部分,指定了哪些函數(Operation)向外公開(即:可供Client調用)。被[OperationContract]修飾的函數可以被客戶端(Client)調用。
[OperationContent]是Attribute。關於Attribute不太明白的,請參考:《別弄混了C#.的幾個小概念Attribute,property,field

 1     public class Service1 : IService1
 2     {
 3         public string GetData(int value)
 4         {
 5             return string.Format("You entered: {0}", value);
 6         }
 7 
 8         public CompositeType GetDataUsingDataContract(CompositeType composite)
 9         {
10             if (composite == null)
11             {
12                 throw new ArgumentNullException("composite");
13             }
14             if (composite.BoolValue)
15             {
16                 composite.StringValue += "Suffix";
17             }
18             return composite;
19         }
20     }

Service1實現了IService接口,是Service Contract 的實現部分。VS自動生成的代碼太簡單了,不解釋了。這里為了盡可能簡單地說明問題。具體項目中,你可能需要連接數據庫增、刪、改、查數據,或對數據按n多復雜的業務規則進行數據處理以后,返回給client,等。
[ServiceContract] Attribute 可以有以下Property 的:

CallbackContract 設置callback的類型:Duplicate指Service Host和Client之間進行雙向通信
ConfigurationName 指定配置文件中某個configuration的名字
HasProtectionLevel 標示是否可以處理安全消息
Name 給contract指定一個名字,在client端可見的名字,默認就是接口名字
Namespace 給消息指定一個命名空間
ProtectionLevel  
SessionMode 指允許,還是不允許,還是強制session

 

 

 

 

 

 

[OperationContract] Attribute 可以有以下Property 的:

Action 對請求設置WS-Addressing 的action
AsynchPattern 異步模式
HasProtectionLevel 消息是否加密,簽名
IsInitiating 表明該函數被調用開始時是否要在server上面初始化一個session
IsOneWay 表明函數被client調用以后,client是否會等待函數返回
IsTerminating 表明該函數被調用結束時是否要在server上面關閉session
Name 設置函數的名字,在client端可見的名字,默認就是函數名字
ProtectionLevel  
ReplyAction 設置函數返回消息的SOAP action

 

 

 

 

 

 

 

 

1.1 我們修改一下Service的默認命名空間,使他更make scene(有意義).

打開上篇中的解決方案WcfFirstDemo.sln

右鍵WebHost項目下面的文件:Service.svc,如下圖:

點擊連接如圖:

得到如圖效果:

默認Namespace是http://tempuri.org/

微軟官方建議:修改Service的Namespace,使其包含:公司域名+項目名+版本號(如:日期表示版本號)

修改項目:WcfFirstDemoServiceLib下面的IService.cs代碼如下:

 1     [ServiceContract(Namespace="http://wwww.cnblogs.com/WCF/2012/07/28")]
 2     public interface IService1
 3     {
 4         [OperationContract]
 5         string GetData(int value);
 6 
 7         [OperationContract]
 8         CompositeType GetDataUsingDataContract(CompositeType composite);
 9       
10     }

右鍵項目WcfFirstDemoServiceLib 選擇重新編譯,成功以后,重新用瀏覽器打開service.svc,得到如下圖:

此時已經改變了Service默認的Namespace了,client端需要更新一下,否則運行client端是會報異常的.操作如下圖:

1.2修改Service的Name.默認情況下定義service的接口部分(如本例:IService)的名字就是Service的名字.但有時需要讓client看到的service的名字跟server端看到的的service名字不一樣.

我們先看一下WCFClient項目下面的app.config

修改WcfFirstDemoServiceLib項目下的IService.cs文件

 1     [ServiceContract(Namespace="http://wwww.cnblogs.com/WCF/2012/07/28",Name="DemoService")]
 2     public interface IService1
 3     {
 4         [OperationContract(Name="GetAge")]
 5         string GetData(int value);
 6 
 7         [OperationContract]
 8         CompositeType GetDataUsingDataContract(CompositeType composite);
 9       
10     }

重新編譯WcfFirstDemoServiceLib項目.更新client端對service的引用.此時你會發現client端app.config文件前后發生了變化:

此時WCFClient所生成的代理類的名字也會變化,你需要修改WCFClient

1    DemoService proxy = null;
1         private void Form1_Load(object sender, EventArgs e)
2         {
3             proxy = new DemoServiceClient("BasicHttpBinding_DemoService");
4 
5         }
1         private void btnGetData_Click(object sender, EventArgs e)
2         {
3             this.tbOutputBox.Text = proxy.GetAge(Convert.ToInt32(this.tbInputbox.Text));
4         }

:上面代碼中DemoService 對應server端IService接口;DemoServiceClient對應server端的Service類.

當client端的app.config文件中只包含一個endpoint時,可以直接用proxy=new DemoServiceClient()傳空參數,當然也可以傳這個endpoint的name進去;但是當app.config包含多個endpoint時必須把endpoint的name傳進去才能new出proxy對象.

2.DataContract.

WCF的Server和client之間利用特定格式的Message(消息)進行通信的。但是我們使用的高級語言:不論在Server端還是在client端,我們處理的業務數據都被封裝成了對象。所以想把server端的對象傳送到client(或相反方向)時,我們必須有能力把這些對象轉換成特定格式的message,到另一端接收到message后再把它轉回成對象。C#的基礎類型(如int,string,float,bool等)可以做到這一點。因為一旦確定了Server端或client所用的編程語言,就可以確定這些基礎類型的內存占用情況(例如:一個Server端定義的int變量在C#中占用多大內存空間是已知的,那么client端即便使用的是其他語言也完全可以計算出該變量的內存占用情況)。可是我們自己定義的類型可是五花八門了(比如:server端定義的Person類new出的object到底占用多大內存空間,就算Server端與client端使用同一種語言,Client端是不知道的Person類的對象的內存占用情況的。)

遇到這種請款下,我們怎么辦呢?這時就輪到[DataContract]露面了。

遇到這種請款下,我們怎么辦呢?這時就輪到[DataContract]露面了。

ServiceContract做的工作是指定service向client提供了哪些函數可供調用。DataContract做的工作就是指定在Server端與client端之間可以傳送的數據。[DataContract]的作用就是指定當需要傳送某個類(如:Person類)的對象時,將該對象轉化成為XML.接受方接到XML以后,再按同樣的方式還原成對象。

[DataContract]Attribute 標在class定義上面一行。[DataMember]Attribute標在Property定義上面一行,field不需要Attribute修飾。

 1     [DataContract]
 2     public class CompositeType
 3     {
 4         bool boolValue = true;
 5         string stringValue = "Hello ";
 6 
 7         [DataMember]
 8         public bool BoolValue
 9         {
10             get { return boolValue; }
11             set { boolValue = value; }
12         }
13 
14         [DataMember]
15         public string StringValue
16         {
17             get { return stringValue; }
18             set { stringValue = value; }
19         }
20     }

[DataContract]Attribute 可以像[ServiceContract]一樣設置Name和Namespace.
[DataMember] Attribute 可以有以下屬性:

EmitDefaultValue 設置一個默認值
IsRequired 進行序列化/反序列化時該值一定不可為空值
Name Property的名字
Order 設置進行序列化/反序列化的順序

 

 

 

 

 2.1修改DataContract的默認namespace , 

 1    [DataContract(Namespace = "http://wwww.cnblogs.com/WCF/2012/07/28", Name = "CompositeTypeDemo")]
 2     public class CompositeType
 3     {
 4         bool boolValue = true;
 5         string stringValue = "Hello ";
 6 
 7         [DataMember(Name="GetBool")]
 8         public bool BoolValue
 9         {
10             get { return boolValue; }
11             set { boolValue = value; }
12         }
13 
14         [DataMember(Name="GetString")]
15         public string StringValue
16         {
17             get { return stringValue; }
18             set { stringValue = value; }
19         }
20     }

這樣在client端看到的類(class)名,函數名與server看到的就不相同.

 3.Fault Contract.

在WCF中處理異常(Exception)的方法有些特殊.我們不能單從server處理exception,需要進一步將Exception從server傳送到client. 在后面我們再單獨討論WCF的Exception處理.

4. Message Contract.

Message Contract與Data Contract都是作用在傳送的對象(object)上面.

不同的是:

datacontract是將object序列化化為xml. 實現object的各個property與xml 文本中各個node(節點)的對應);

messagecontract將對象組裝成message(指定Message的Header,body).實現的是object各個property與消息的各個元素的對應.

具體的深層區別於聯系,以及使用場景,我還不懂,希望有朋友對着塊比較懂的,可以交流一下.如果后面等我弄懂了的話,我再專門寫博文交流.

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM