WCF寄宿方式是一種非常靈活的操作,可以在IIS服務、Windows服務、Winform程序、控制台程序中進行寄宿,從而實現WCF服務的運行,為調用者方便、高效提供服務調用。本文分別對這幾種方式進行詳細介紹並開發例子進行說明,以求大家對WCF寄宿的方式進行全面的認識和了解。
1、 WCF服務的IIS服務寄宿
我在我前面幾篇WCF開發框架的介紹文章中,介紹過了WCF常用的一種寄宿方式,IIS服務寄宿。這種寄宿方式是最為方便的方式,而且由於服務只需要IIS運行就能自動運行起來,因此廣為使用。
創建這種方式IIS寄宿方式的,只需要在解決方案里面,添加WCF服務應用程序,就可以生成這種的服務模塊了。

這個是一個基於Web的應用程序,創建項目后會生成一個Service1.svc的服務頁面,以及相關的WCF服務接口和實現,如下圖所示。

這個就是簡單的WCF服務,當然如果是復雜的實際應用,會考慮和數據庫打交道,而且可能項目會分成幾個進行管理,從而實現更好的邏輯分離操作。
2、 創建WCF服務庫為多種寄宿做准備
除了上面常用的IIS服務寄宿,一般還會有各種各樣的寄宿方式,不過如果采用其他方式的寄宿方式,一般會把WCF服務和寄宿方式進行項目的分離,實現更好的重用操作,特別WCF需要考慮多種寄宿方式的情況下。下面是WCF服務庫和WCF服務應用程序的介紹說明,先了解一下基礎。
WCF服務庫,可以認為是一個包含WCF服務以及契約定義的類庫。這里WCF服務庫還不能直接運行,你可以在其他項目里引用,在宿主里啟用托管這個庫。
而WCF應用程序,是一個可以執行的程序,它有獨立的進程,WCF服務類契約的定義,可以直接看到運行的效果。此項目模板應該是基於IIS托管的程序。
前者一般考慮WCF服務設計的時候,服務類的定義為單獨的庫,可以為其它項目使用。提高代碼的復用性。后者在開發基於IIS托管的WCF服務程序時,比較多見,自學的時候也可以使用這種類型。當然你也可以修改這些代碼,比如把WCF服務程序里的類,移到一個單獨的類庫里。
創建WCF服務庫,可以理解為我們開發.NET程序時創建的一個類庫模塊,不含界面,如下所示,創建一個WCF服務庫。

確定后就只有一個示例服務Service1生成了。

這里,我們為了演示,就不修改任何它們的代碼,原始的代碼如下所示。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace WcfServiceLibrary
{
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
}
3、 WCF服務的控制台程序寄宿
這種也是一種常見的WCF服務寄宿方式,通過啟動一個類似DOS窗口的控制台軟件,實現WCF服務的動態寄宿,關閉控制台程序,服務就自然終止。
這種方式很簡單,創建一個控制台程序,然后添加WCF服務類庫的項目應用,在Main函數里面添加下面代碼即可實現。
namespace WcfService_HostConsole
{
class Program
{
static void Main(string[] args)
{
try
{
ServiceHost serviceHost = new ServiceHost(typeof(Service1));
if (serviceHost.State != CommunicationState.Opened)
{
serviceHost.Open();
}
Console.WriteLine("WCF 服務正在運行......");
Console.WriteLine("輸入回車鍵 <ENTER> 退出WCF服務");
Console.ReadLine();
serviceHost.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}

4、 WCF服務的Winform程序寄宿
和控制台程序一樣,我們創建一個Winform項目,然后在窗體啟動代碼里面添加寄宿方式的代碼即可,為了較好的響應體驗,可以使用后台線程程序進行服務啟動,如下所示。
namespace WcfService_HostWinform
{
public partial class FrmMain : Form
{
ServiceHost serviceHost = null;
BackgroundWorker worker = null;
public FrmMain()
{
InitializeComponent();
worker = new BackgroundWorker();
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
if (!worker.IsBusy)
{
tssTips.Text = "正在啟動......";
lblTips.Text = tssTips.Text;
worker.RunWorkerAsync();
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
serviceHost = new ServiceHost(typeof(Service1));
if (serviceHost.State != CommunicationState.Opened)
{
serviceHost.Open();
}
e.Result = "正常";
}
catch (Exception ex)
{
e.Result = ex.Message;
}
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Result != null)
{
if (e.Result.ToString() == "正常")
{
tssTips.Text = "服務正在進行偵聽......";
}
else
{
tssTips.Text = string.Format("錯誤:{0}", e.Result);
}
lblTips.Text = tssTips.Text;
}
}
...........................
}
}
當然為了防止Winform程序被不小心關閉,可以添加托盤代碼,把程序縮小到托盤圖標里面。

5、 WCF服務的Windows 服務程序寄宿
這種方式的服務寄宿,和IIS一樣有一個一樣的優點,系統啟動后,WCF服務也會跟着啟動了,不用人工干預,也是一種較好的寄宿方式。
為了實現這種方式的寄宿,我們創建一個控制台程序,然后添加響應的Window服務和安裝程序類

然后在服務類啟動里面添加WCF的寄宿代碼,如下所示。
public class ServiceManager : ServiceBase
{
private static object syncRoot = new Object();//同步鎖
private ServiceHost serviceHost = null; //寄宿服務對象
public ServiceManager()
{
this.ServiceName = Constants.ServiceName;
}
/// <summary>
/// 設置具體的操作,以便服務可以執行它的工作。
/// </summary>
protected override void OnStart(string[] args)
{
try
{
serviceHost = new ServiceHost(typeof(Service1));
if (serviceHost.State != CommunicationState.Opened)
{
serviceHost.Open();
}
}
catch (Exception ex)
{
LogTextHelper.Error(ex);
}
LogTextHelper.Info(Constants.ServiceName + DateTime.Now.ToShortTimeString() + "已成功調用了服務一次。");
LogTextHelper.Info(Constants.ServiceName + "已成功啟動。");
}
為了實現通過該控制台程序實現參數化安裝和卸載服務,我們需要攔截控制台的參數,並進行相應的操作,如下所示。
/// <summary>
/// 應用程序的主入口點。
/// </summary>
[STAThread]
static void Main(string[] args)
{
ServiceController service = new ServiceController(Constants.ServiceName);
// 運行服務
if (args.Length == 0)
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new ServiceManager() };
ServiceBase.Run(ServicesToRun);
}
else if (args[0].ToLower() == "/i" || args[0].ToLower() == "-i")
{
#region 安裝服務
if (!ServiceIsExisted(Constants.ServiceName))
{
try
{
string[] cmdline = { };
string serviceFileName = System.Reflection.Assembly.GetExecutingAssembly().Location;
TransactedInstaller transactedInstaller = new TransactedInstaller();
AssemblyInstaller assemblyInstaller = new AssemblyInstaller(serviceFileName, cmdline);
transactedInstaller.Installers.Add(assemblyInstaller);
transactedInstaller.Install(new System.Collections.Hashtable());
TimeSpan timeout = TimeSpan.FromMilliseconds(1000 * 10);
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
}
catch (Exception ex)
{
LogTextHelper.Info(ex);
throw;
}
}
#endregion
}
else if (args[0].ToLower() == "/u" || args[0].ToLower() == "-u")
{
#region 刪除服務
try
{
if (ServiceIsExisted(Constants.ServiceName))
{
string[] cmdline = { };
string serviceFileName = System.Reflection.Assembly.GetExecutingAssembly().Location;
TransactedInstaller transactedInstaller = new TransactedInstaller();
AssemblyInstaller assemblyInstaller = new AssemblyInstaller(serviceFileName, cmdline);
transactedInstaller.Installers.Add(assemblyInstaller);
transactedInstaller.Uninstall(null);
}
}
catch (Exception ex)
{
LogTextHelper.Info(ex);
throw;
}
#endregion
}
}
編譯程序成功后,我們添加兩個批處理的DOS腳本來實現執行程序的自動安裝和卸載,如下所示。
安裝腳本
"WcfService_HostWinService.exe" -i pause
卸載腳本
"WcfService_HostWinService.exe" -u pause

順利執行腳本后,服務列表里面就增加一個服務項目了。

卸載操作,直接執行腳本就會卸載服務,非常方便哦。
6、 WCF服務的Web寄宿
當然,除了以上幾種方式,這種以WCF服務庫的方式,也可以在Web方式進行寄宿(IIS方式),這種方式更簡單,添加一個后綴名的svc的文件,只需要一行代碼即可,如下所示。

7、 使WCF服務支持GET方式調用
有時候,我們為了需要,可能通過一個小程序發布一個服務,然后供其他程序進行調用,可能是Web,也可以是Winform,但是我們是想提供一個基於HTTP,GET或者POST方式來實現接口的調用的,例如,提供一個JSON格式或者文本格式的內容返回操作。
如果是整合在Winform里面,那么我們在Winform里面添加一個WCF的項,修改里面的代碼就可以了,如下所示。

首先要在使用GET方式的WCF服務接口的添加說明。如果是POS方式,增加設置有點不同([WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)])。
namespace WcfServiceForWinform
{
[ServiceContract]
public interface IService1
{
[OperationContract]
void DoWork();
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json)]
string GetData(int value);
}
}
第二,在實現類里面添加相應的設置
namespace WcfServiceForWinform
{
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1 : IService1
{
public void DoWork()
{
}
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
}
配置文件如下所示,顏色標注特別的要注意:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true"/>
</system.web>
<system.serviceModel>
<services>
<service name="WcfServiceForWinform.Service1" behaviorConfiguration="ServiceConfig">
<endpoint address="" binding="webHttpBinding"
bindingConfiguration="webHttpBindingWithJsonP" behaviorConfiguration="webHttpBehavior"
contract="WcfServiceForWinform.IService1">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:9000/Service1/" />
</baseAddresses>
</host>
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingWithJsonP" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="webHttpBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceConfig">
<serviceMetadata httpGetEnabled="True" policyVersion="Policy15"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
運行Winform程序,啟動了WCF服務后,我們可以在瀏覽器(Chrome)上進行操作,如下結果所示。

從上圖我們可以看到,這個通過Winform啟動起來的WCF服務,連接也能通過GET方式進行接口調用了,接口可以通過參數進行傳遞,對於一些方便傳輸數據的接口如JSON接口,就是一種非常方便的調用了。

