程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 《WCF技術內幕》翻譯18:第1部分_第4章_WCF101:從外部剖析WCF

《WCF技術內幕》翻譯18:第1部分_第4章_WCF101:從外部剖析WCF

編輯:關於.NET

盡管WCF是一個相當復雜的平台,但對於偶然的一個學習者來說它看起來還是 相當簡單的。正如你在Hello WC例子裡看到的一樣,構建一個接受程序可以簡化 為使用地址、綁定和契約配置一個或者多個終結點。構建一個發送程序可以簡單 理解為使用一個地址、綁定和契約向接收終結點發送消息。如果我們要修改發送 者或者接收者的處理過程,我們可以隨便這麼做,使用我們自己的行為配置或者 使用WCF的自帶行為(比如增加元數據支持)。圖4-1展示了Endpoints、 addresses、bindings、contracts和behaviors之間的關系。

圖4-1:Endpoints、 addresses、bindings、contracts和behaviors

地址

所有發送或者接收消息的程序必須在終結點上使用某個地址。例如,接收程 序在某個地址上偵聽請求消息,而發送程序發送消息到目標地址。WCF 接收基礎 結構依賴System.Uri類型去構建接收終結點。WCF發送基礎結構,換句話說,依 賴 System.ServiceModel.EndpointAddress類型發送消息給最終接收者。 System.ServiceModel.EndpointAddress類型是對WS-Addressing 中終結點參考 規范的CLR抽象,發送者使用這個類型去為請求消息添加終結點信息,並與接收 終結點建立連接(如果存在接收終結點)第5章包含了EndpointAddress類型的詳 細介紹。

在WCF裡,地址在某些形式上,是一個URI(EndpointAddress對象包裝了一個 System.Uri對象)。一個關鍵部分就是URI裡的scheme名。Scheme是URI表示的標 識符的抽象,scheme名是一種標識scheme的方式。在許多情況下,scheme名匹配 可以定位資源的協議,因此使用URI作為URL。例如,URI http://localhost:5000/IHelloWCF標識http為scheme名,並且如此偶然的是 http(超文本傳輸協議)也是一個傳輸模式。在內部看,WCF基礎結構必須能夠使 用URInate去構建發送或者接收基礎結構。

綁定

綁定是我們表示消息應用如何處理、發送和接收消息的主要方式。更確切地 說,它表示傳輸、WS-*協議、安全需求、事務需求和終結點的主要方式。WCF包 含9種覆蓋傳輸、WS-*協議、安全需求、事務需求的綁定。如果這些綁定不能滿 足我們的需求,我們還可以定義符合我們特定需求的綁定。

通常來說,綁定是定義消息基礎結構的一個類型;它是我們程序支持傳輸和 協議的一個抽象層。對於開發人員,這個抽象意味著通過TCP/IP傳輸發送消息的 代碼和通過MSMQ發送消息的代碼看起來非常相似,因此把我們的程序從特定的傳 輸或者協議裡解耦。此種方式的松耦合意味著開發人員可以開發、改變和定制一 個應用比以前更快地滿足客戶要求。

所有的綁定類型都是System.ServiceModel.Channels.Binding的子類型,於 是它們都有相同的屬性。一個共同的屬性就是他們維護者一個私有 System.ServiceModel.Channels.BindingElement對象的列表。一個 BindingElement 是消息交換一個特定方面的抽象,像傳輸或者WS-*協議。所有 的綁定暴露了一個名為CreateBindingElements的方法,這個方法可以構建和返 回特定綁定元素的列表。下面展示的是一個簡單程序,它包含WCF裡的9種綁定, 並迭代顯示它們的BindingElement列表:

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Reflection;
using System.Collections.Generic;
using System.ServiceModel.MsmqIntegration;

sealed class BindingElementsShow
{
  static void Main(){
     List<Binding> bindings = new List<Binding> ();
     bindings.Add(new BasicHttpBinding());
     bindings.Add(new NetNamedPipeBinding());
     bindings.Add(new NetTcpBinding());
     bindings.Add(new WSDualHttpBinding());
     bindings.Add(new WSHttpBinding());
     bindings.Add(new NetMsmqBinding());
     bindings.Add(new MsmqIntegrationBinding());
     bindings.Add(new WSFederationHttpBinding());
     // throws if Peer Networking not installed
     bindings.Add(new NetPeerTcpBinding());

     ShowBindingElements(bindings);
  }

  private static void ShowBindingElements(List<Binding>  bindings){
     foreach (Binding binding in bindings){
       Console.WriteLine("Showing Binding Elements for  {0}",
         binding.GetType().Name);
       foreach (BindingElement element in  binding.CreateBindingElements()){
         Console.WriteLine("\t{0}", element.GetType ().Name);
       }
     }
  }
}

程序輸入如下:

Showing Binding Elements for BasicHttpBinding
         TextMessageEncodingBindingElement
         HttpTransportBindingElement
Showing Binding Elements for NetNamedPipeBinding
         TransactionFlowBindingElement
         BinaryMessageEncodingBindingElement
         WindowsStreamSecurityBindingElement
         NamedPipeTransportBindingElement
Showing Binding Elements for NetTcpBinding
         TransactionFlowBindingElement
         BinaryMessageEncodingBindingElement
         WindowsStreamSecurityBindingElement
         TcpTransportBindingElement
Showing Binding Elements for WSDualHttpBinding
         TransactionFlowBindingElement
         ReliableSessionBindingElement
         SymmetricSecurityBindingElement
         CompositeDuplexBindingElement
         OneWayBindingElement
         TextMessageEncodingBindingElement
         HttpTransportBindingElement
Showing Binding Elements for WSHttpBinding
         TransactionFlowBindingElement
         SymmetricSecurityBindingElement
         TextMessageEncodingBindingElement
         HttpTransportBindingElement
Showing Binding Elements for NetMsmqBinding
         BinaryMessageEncodingBindingElement
         MsmqTransportBindingElement
Showing Binding Elements for MsmqIntegrationBinding
         MsmqIntegrationBindingElement
Showing Binding Elements for WSFederationHttpBinding
         TransactionFlowBindingElement
         SymmetricSecurityBindingElement
         TextMessageEncodingBindingElement
         HttpTransportBindingElement
Showing Binding Elements for NetPeerTcpBinding
         PnrpPeerResolverBindingElement
         BinaryMessageEncodingBindingElement
         PeerTransportBindingElement 

在我們的輸出力,你同樣可以看到每個繼承自Binding的綁定類型都表示一個 消息屬性的集合。在運行時,綁定元素列表的內容會決定我們程序裡的終結點的 消息屬性。換句話說,我們選擇的終結點綁定會對我們應用發送和接收的消息產 生直接影響。因此,了解特定綁定的消息屬性對於成功實現WCF系統至關重要。 表4-1展示了每個WCF綁定的重要屬性。

當一個人第一次接觸這些WCF默認的綁定時,很容易被選擇綁定和選擇綁定合 適的消息選項而迷惑。記住當選擇的時候,它可以托管多個終結點。如果我們構 建和部署一個通過HTTP接收Text編碼的消息應用的時候,我們也能夠增加通過 TCP接收二進制編碼的消息的終結點.很大程度上,綁定是我們表示終結點消息基 礎結構的主要方式。第8章介紹了綁定的詳細內容。

契約

契約把面向對象的結構映射為消息結構。更確切地說,契約定義了程序裡的 終結點、終結點使用的 MEP和終結點處理的消息結構。例如,契約可以幫助我們 把消息體的schema映射為.NET Framework類型定義,因此,可以簡化那些產生匹 配schema的消息的代碼。WCF裡定義了三種契約類型:服務契約、數據契約和消 息契約。服務契約描述了終結點的操作。描述包含名稱、MEP、會話規范信息、 請求和響應的消息頭和每個操作的安全信息。數據契約,換句話說,映射消息體 到一個或者多個操作。消息契約映射消息體和消息頭到一個或者多個操作。

注釋:所有的契約都是有注釋的類型或者類型定義,注釋中使用的屬性決定 了這個類型定義是服務、數據或者消息契約。重要的是要記住注釋一個類型或者 成員定義只是簡單地在類型的元數據增加一些信息。因此屬性定義都是惰性的。 要想確定特定屬性的存在必須要求代碼通過反射API查詢元數據。在WCF契約裡, WCF基礎結構查詢元數據的契約定義並基於元數據的內容執行操作。也可以手動 完成這些工作,契約是可選擇的。實際上說,WCF基礎結構根據契約定義干的是 有些無聊的工作,所以實際上你編寫的WCF程序應該使用契約。我在第9章裡詳細 介紹了這些內容。

通過類型注釋構建一個契約本質上是晚綁定【老徐注釋1】。雖然這是WCF提 供給開發者擴展性和適應性的主要方式之一,它也意味著不一致性或者不兼容性 或許只有在運行時才能捕獲。

服務契約

服務契約表示終結點暴露的操作,並且這些操作也被消息交換中的發送者和 接受者使用。接受程序可以使用服務契約去構建偵聽請求消息的基礎結構。發送 程序可以使用服務契約構建發送到消息接受終結點的消息結構。服務契約裡的信 息都包含每個操作的名字,操作的參數,action頭與操作、操作會話規范信息關 聯起來。

在元素級別,服務契約式一個被ServiceContractAttribute或者 OperationContractAttribute屬性標記的類或者接口。 ServiceContractAttribute可以使用在類和接口上,而 OperationContractAttribute 只能用在方法上。絕大部分標記了 OperationContractAttribute的類型成員都會被 ServiceContractAttribute標 記,一個例外就是雙工服務契約。重新提示一下,我會再第9章裡詳細說明契約 問題。

數據契約

數據契約映射.NET Framework類型到消息體。如果SOAP是選擇的消息結構, 數據契約就可以映射.NET Framework類型到SOAP消息體的schema。像任何WCF契 約,數據契約也是一個標記類型定義,使用的屬性就是 DataContractAttribute 和DataMemberAttribute。大部分時間,服務契約使用數據契約,如下所示:

[ServiceContract]

interface ISomeServiceContract {
  [OperationContract]
  void SomeOperation(SomeDataContract info); // notice the  argument type注意參數類型
}

[DataContract()]
sealed class SomeDataContract {
  [DataMember]
  Int32? number;

  String status;

  [DataMember] // must have getter and setter
  internal String Status {
     get { return status; }
     set { status = value; }
  }

  internal Int32? Number {
     get { return number; }
  }

  internal SomeDataContract(Int32? number) : this(number,  null)
  {
  }

  internal SomeDataContract(Int32? number, String status)  {
     this.number = number;
     this.status = status; // consider the null case
  }
}

在這個例子裡,ISomeServiceContract接口定義了一個可以接受 SomeDataContract類型的方法。因為SomeDataContract被標記了 DataContractAttribute,發送到SomeOperation操作的消息體將會包含一個符合 SomeDataContract類型的schema.

消息契約

消息契約映射.NET Framework類型到消息結構上。如果XML是消息的結構,那 麼消息契約會映射.NET Framework類型到消息的schema上。這包含消息頭和消息 體,如下所示:

[ServiceContract]

interface ISomeServiceContract {
  [OperationContract]
  void SomeOperation(SomeDataContract info); // notice the  argument type
  [OperationContract]
  void SomeOtherOperation(SomeMessageContract info); // notice  the argument type
}

[DataContract()]
sealed class SomeDataContract {
  [DataMember]
  Int32? number;

  String status;

  [DataMember] // must have getter and setter
  internal String Status {
     get { return status; }
     set { status = value; }
  }

  internal Int32? Number {
     get { return number; }
  }

  internal SomeDataContract(Int32 number) : this(number,  null)
  {
  }

   internal SomeDataContract(Int32 number, String status)  {
     this.number = number;
     this.status = status; // consider the null case
  }
}

[MessageContract]
sealed class SomeMessageContract {

     SomeMessageContract() { } // must have default  constructor必須包含默認的構造函數

     [MessageHeader]
     Int32? SomeNumber;

     [MessageBodyMember]
     SomeDataContract messageBody;

     internal SomeMessageContract(Int32? someNumber) {
         SomeNumber = someNumber;
         messageBody = new SomeDataContract (someNumber);
     }
}

注意到ISomeServiceContract接口的包含一個接受 SomeMessageContract 類 型參數的SomeOtherOperation的方法。這很正常因為SomeMessageContract 包含 MessageContractAttribute的屬性定義。這裡是一些簡單的介紹契約的內容,我 們會再第9章裡詳細討論這些主題。

【老徐注釋】

1.早綁定指在對象申明的時候就和他的類型建立了關聯,晚綁定是指我們的 代碼在運行時再檢查對象是否提供了我們所需要的方法和屬性。

早綁定的優點是:

* 編譯效率

* 代碼提示(代碼智能感知)

* 編譯時類型檢查

晚綁定的優點是:

* 不用申明類型

* 對象類型可以隨時更改

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved