WCF服務承載(筆記)

Halower發表於2013-07-09

自託管(也做自承載)

    承載 WCF 服務最靈活、最便捷的方法就是進行自承載。要能夠自承載服務,必須滿足兩個條件。第一,需要 WCF 執行時;第二,需要可以承載 ServiceHost 的託管 .NET 應用程式。您需要自己動手編寫啟動和停止宿主的程式碼。

什麼時候使用自託管?

        當應用程式的各個元件之間需要相互通訊,或者在一個本地環境中,客戶端和事務的數量都十分受限是常使用自託管。對於企業級方案來說不應考慮自承載方式。自承載適用於企業專案的開發或演示階段。此外,當您希望使用者桌面應用程式進行相互通訊或在點對點情況下,可以對服務進行自承載。

自承載的優點:

• 易用性:只需幾行程式碼即可使服務執行。

• 靈活性:通過 ServiceHost<T> 的 Open() 和 Close() 方法,可以輕鬆控制服務的生存期。

• 易除錯性:可以使用熟悉的除錯方式對自承載環境中承載的 WCF 服務進行除錯,而不必連線到單個應用程式來啟用服務。

• 易部署性:通常,部署簡單 Windows 應用程式與使用 xcopy 一樣容易。您不必在伺服器場和類似地方部署複雜的方案,即可部署簡單的 Windows 應用程式來充當 WCF ServiceHost。

• 支援所有繫結和傳輸:自承載並不限制您僅能使用現有的繫結和傳輸技術。在 Windows XP 和 Windows Server 2003 上,IIS 限制您只能使用 HTTP。(備註:II6以下)

 下面是自承載的缺點:

•可用性受到限制:服務只有在應用程式執行時才能被訪問。
•功能受到限制:自承載的應用程式在對高可用性、易管理性、可靠性、可恢復性、版本控制和部署方案的支援方面受到一定限制。至少,現有的 WCF 無法提供這些支援,因此在自承載的情況中,您必須自己實現這些功能;例如,預設情況下 IIS 提供了這些功能中幾項。

下面是一個小例子

 1 using System.ServiceModel;
 2 
 3 namespace Halower.SelfHost
 4 {
 5     [ServiceContract(Namespace = "http://www.cnblogs.com/rohelm")]
 6     public interface ICalcuContract
 7     {
 8         [OperationContract]
 9         double Add(int x, int y);
10 
11         [OperationContract]
12         double Substrate(int x, int y);
13 
14         [OperationContract]
15         double Multiply(int x, int y);
16 
17         [OperationContract]
18         double Divide(int x, int y);
19     }
20 }
ICalcuContract
 1 namespace Halower.SelfHost
 2 {
 3     public class CalculatorService : ICalcuContract
 4     {
 5         public double Add(int x, int y)
 6         {
 7             return x + y;
 8         }
 9 
10         public double Substrate(int x, int y)
11         {
12             return x - y;
13         }
14 
15         public double Multiply(int x, int y)
16         {
17             return x * y;
18         }
19 
20         public double Divide(int x, int y)
21         {
22             return x / y;
23         }
24     }
25 }
CalculatorService
 1 using System;
 2 using System.ServiceModel;
 3 using System.ServiceModel.Description;
 4 
 5 namespace Halower.SelfHost
 6 {
 7     internal class Program
 8     {
 9         private static void Main(string[] args)
10         {
11             Uri[] baseAddresses = new Uri[] {
12                 new Uri("http://localhost:10101/CalculatorService"),
13                  new Uri("net.tcp://localhost:10102/CalculatorService")
14             };
15             using (ServiceHost host = new ServiceHost(typeof(CalculatorService), baseAddresses))
16             {
17                 host.AddDefaultEndpoints();
18                 try
19                 {
20                     host.Open();
21                     Console.WriteLine("WCF服務已經啟動!");
22                     foreach (var endpoint in host.Description.Endpoints)
23                     {
24                         Console.WriteLine("\t" + endpoint.Address.Uri.ToString());
25                     }
26                     Console.ReadKey();
27                 }
28                 catch (CommunicationException ex)
29                 {
30                     host.Abort();
31                 }
32             }
33         }
34     }
35 }
Host

  雖然我們知道每一個服務的實現只能有一個serviceHost,但是可以公開多個終結點和介面,同理,我們可以在同一個程式中建立多個serviceHost,而且我們有時候有需求控制他們的啟動順序,我們就是可以嘗試著使用一下serviceHost非同步啟動的方式

 1 using System;
 2 using System.ServiceModel;
 3 
 4 namespace Halower.SelfHost
 5 {
 6     internal class Program
 7     {
 8         private static void Main(string[] args)
 9         {
10             Uri[] baseAddresses = new Uri[] {
11                 new Uri("http://localhost:10101/CalculatorService"),
12                  new Uri("net.tcp://localhost:10102/CalculatorService")
13             };
14             using (ServiceHost host = new ServiceHost(typeof(CalculatorService), baseAddresses))
15             {
16                 host.AddDefaultEndpoints();
17                 IAsyncResult result = host.BeginOpen(new AsyncCallback(ServiceHostOpenCallBack), null);
18                 while (!result.IsCompleted)
19                 {
20                     Console.WriteLine("做一些與服務無關的事情");
21                 }
22                 Console.ReadKey();
23             }
24         }
25 
26         private static void ServiceHostOpenCallBack(IAsyncResult ar)
27         {
28             Console.WriteLine("服務1已經啟動!");
29             ServiceHost host2 = new ServiceHost(typeof(CalculatorService), new Uri("http://localhost:10103/CalculatorService"));
30             Console.WriteLine("服務2即將啟動!");
31             host2.Open();
32             Console.WriteLine("服務2已經啟動!");
33             host2.Close();
34         }
35     }
36 }
ServiceHost使用非同步

什麼有時候需要自定義serviceHost?

  有些時候,我們需要在不同的地方重用配置引數相同的同一個ServiceHost類,例如,我們已經建立了一個ServiceHost物件,可以用編碼的方式控制服務配置或者部分配置。在這種情況下,如果使用這個類,就需要擴充套件並編寫自定義的ServiceHost類的實現。

  例如,.NET Framework 提供了專門宿主實現,都極大的方便了我們的操作,而不去自己配置某些關鍵項:

  WorkflowServiceHost 類,為基於工作流的服務提供宿主。

  WebServiceHost 類,它是對 Windows Communication Foundation (WCF) REST 程式設計模型的補充  

 1 [ServiceContract]
 2 public interface ICalculator
 3 {
 4     [OperationContract]
 5     [WebInvoke(UriTemplate = "add?x={x}&y={y}")]
 6     long Add(long x, long y);
 7 
 8     [OperationContract]
 9     [WebInvoke(UriTemplate = "sub?x={x}&y={y}")]
10     long Subtract(long x, long y);
11 
12     [OperationContract]
13     [WebInvoke(UriTemplate = "mult?x={x}&y={y}")]
14     long Multiply(long x, long y);
15 
16     [OperationContract]
17     [WebInvoke(UriTemplate = "div?x={x}&y={y}")]
18     long Divide(long x, long y);
19 
20     [OperationContract]
21     [WebGet(UriTemplate = "hello?name={name}")]
22     string SayHello(string name);
23 }
24 
25 public class CalcService : ICalculator
26 {
27     public long Add(long x, long y)
28     {
29         return x + y;
30     }
31 
32     public long Subtract(long x, long y)
33     {
34         return x - y;
35     }
36 
37     public long Multiply(long x, long y)
38     {
39         return x * y;
40     }
41 
42     public long Divide(long x, long y)
43     {
44         return x / y;
45     }
46 
47     public string SayHello(string name)
48     {
49         return "Hello " + name;
50     }
51 }
52 
53 class Program
54 {
55     static void Main(string[] args)
56     {
57         Uri baseAddress = new Uri("http://localhost:8000/");
58 
59         WebServiceHost svcHost = new WebServiceHost(typeof(CalcService), baseAddress);
60 
61         try
62         {
63             svcHost.Open();
64 
65             Console.WriteLine("Service is running");
66             Console.WriteLine("Press enter to quit...");
67             Console.ReadLine();
68 
69             svcHost.Close();
70         }
71         catch (CommunicationException cex)
72         {
73             Console.WriteLine("An exception occurred: {0}", cex.Message);
74             svcHost.Abort();
75         }
76     }
77 }
WebServiceHostDemo

    自定義ServiceHost類說起來用以做起來難,簡單的說,如果我們直接繼承自ServiceHost,我們要從讀取配置檔案讀取引數後修改他們就重寫ServiceHost類的ApplyConfiguration,如果是在宿主建立之前修改配置引數,就可重寫ServiceHost類的Opening方法

IIS承載 

  在 IIS 上的 Web 服務開發長期以來一直是 ASP.NET 的領地。ASP.NET 1.0 釋出後,Web 服務框架成為它的一部分。Microsoft 利用 ASP.NET HTTP 管道使 Web 服務在 Windows 平臺上成為現實。遺憾的是,ASP.NET 和 Web 服務之間的這種緊密耦合在面向服務的世界中產生了幾個限制,對 HTTP 的依賴性是主要原因。在不同宿主上執行 ASP.NET HTTP 管道很困難,因此很少採用這種方案。甚至在此後,ASP.NET Web 服務(也稱為 ASMX 服務)在部署方案和配置依賴性方面一直是非常面向 Web 的。Microsoft 最初發布了幾個版本的 Web 服務增強 (WSE),以彌補 ASP.NET Web 服務的某些侷限,尤其是消除在實現 WS-* 協議方面的限制。但是,WSE 非常依賴於 ASP.NET Web 服務實現。
WCF 服務採用了完全不同的途徑來實現面向服務。WCF 的統一程式設計模型基於嚴格分層的模型,以分解面向 Web 的範例,並使服務模型和通道層與受支援的傳輸方式斷開連線。此模型允許 WCF 支援幾個不同的宿主,其中 IIS 是最重要的。
構建 WCF 是為了支援 Windows XP、Windows Server 2003、Windows Vista 和 Windows Server 2007。自從 IIS 5.1(與 Windows XP 一起釋出)以來,有了很多變化。但是,Microsoft 仍然繼續支援舊版上的 WCF。這可能是因為 Microsoft .NET Framework 和 CLR 提供的功能所導致的,該功能是構建 WCF 的基礎。

  IIS 7.0 推動了 Web 伺服器領域中的又一重大演進。可以在圖中看到兩個重要改變。第一,現在特定於協議的偵聽器介面卡支援所有四種 WCF 傳輸,而不是僅限於 IIS 6.0 中的 HTTP 傳輸。此外,出現了稱為 Windows 啟用服務 (WAS) 的新作業系統服務。W3svc.exe 和 WAS 都執行在稱為 SvcHost.exe 的作業系統宿主的內部。為了能夠將 IIS 6.0 程式模型的強大功能與 WCF 結合使用,則需要進行這些更改。您可能會問“為什麼?”好的,WCF 服務也工作在 IIS 5.1 和 IIS 6.0 中,那麼,通過在 IIS 中推廣程式模型和啟用功能可以獲得什麼好處呢?很簡單:通過推廣啟用概念使它與協議無關,而不是繫結到 HTTP,可以將平臺的啟用功能擴充套件到幾乎所有傳輸型別。

.

IIS 7.0 程式模型體系結構 

 

  HTTP、TCP/IP、命名管道和 MSMQ 的特定於協議的偵聽器介面卡執行於它們自己的程式內部,並將特定傳輸橋接到 WAS。偵聽器介面卡要求 WAS 啟用工作程式,然後將實際通訊轉交給這些工作程式內部的特定協議處理程式。因此,WAS 現在擁有 W3svc.exe 中具備的所有功能。通過將此責任拆分成多個單獨的程式,其他三種傳輸也受益於過去內建在 IIS 6.0 中但只用於 HTTP 的程式模型和啟用功能。總而言之,使用 IIS 7.0 可以跨越 IIS 中提供的任何傳輸型別承載任何 WCF 服務

      IIS承載WCF服務的功能建立在Asp.net HTTP管道的基礎上,這意味著這類宿主你支援HTTP/HTTPS傳輸協議。ASP.NET HTTP 管道有HTTP處理器(HTTP Handler)和HTTP模組(HTTP Module)兩個概念。儘管HTTP處理器是一個特殊類,可以用它截獲及處理傳入及傳出的資訊,但是HTTP處理器會專門負責處理特定的訊息。當吧一個副檔名對映到一個實現IHttpHandler介面的類時,就會啟動HTTP處理器。在WCF環境下,.svc檔案是用來標識服務的副檔名。

IIS承載WCF服務的的實現很簡單,可是使用VS的一鍵釋出工具輕鬆完成,以下是幾個需要注意的地方:

  •      1.按需選擇啟用HTTP非HTTP協議功能
  •   2.為新建的網站按需新增的協議型別的繫結,為相應的應用程式也新增必須的協議
  •   3.如果安裝了 .NET Framework 4,隨後啟用了 .NET Framework 3.5WCF HTTP 啟用,則會發生如下錯誤。 

     若要解決該問題,請在 Visual Studio 命令提示符下執行下面的命令列:aspnet_regiis.exe -i -enable

相關文章