內容摘要
這一篇文章探討使用網站作為WCF服務宿主的幾種做法,我將從最基本的svc文件的方式,演化成為無svc文件的方式,並且在最后介紹REST與路由規則結合的做法。
本文所講解的WCF功能,是基於WCF 4.0這個版本。我所采用的開發工具是Visual Studio 2012. 本文范例代碼可以通過 Web-host-sample.zip 下載。
本文不是WCF的入門文檔,有關WCF的典型使用場景和一些基礎知識,可以參考我之前的兩篇文章
范例說明
本文所采用的范例是相當簡單的,我已經定義的合約和服務如下
using System.ServiceModel; namespace Web { [ServiceContract] public interface IHelloService { [OperationContract] string SayHello(); } public class HelloService : IHelloService { public string SayHello() { return "Hello,world"; } } }
基本做法(采用svc文件的方式)
WCF 4.0以前的版本,我們都是采用svc文件作為服務的宿主文件。例如,我們可以定義如下這樣一個HelloService.svc,其內容如下
<%@ ServiceHost Service="Web.HelloService" %>
需要注意的是,你在Visual Studio中無法直接添加一個空白的svc文件,我一般是選擇Text File這個模板,但是在命名的時候,將其修改為svc后綴。如下圖所示
定義好這個文件后,可以直接在瀏覽器中查看該服務的描述,如下圖所示。此時表示該服務已經被正確地宿主了。
無svc文件的做法
上面這個做法雖然不難,但每次都要手工創建那個svc文件,總是覺得有些多余。那么是否有辦法免去這個步驟呢?WCF 4.0提供了這種可能性。
我們需要做的是,在配置文件中指定一個虛擬的文件路徑,並且將其與服務進行關聯起來。如下所示(請重點關心粗體部分)
<?xml version="1.0"?> <!-- For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5" /> </system.web> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="true"/> </behavior> </serviceBehaviors> </behaviors> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"> <serviceActivations> <add service="Web.HelloService" relativeAddress="MyService.svc"/> </serviceActivations> </serviceHostingEnvironment> </system.serviceModel> </configuration>
為了與上面的例子區分,我特意在這里定義relativeAddress的時候,用了不一樣的名稱。你沒有看錯,只需要這樣定義就可以直接訪問到MyService.svc,而不要求你實際去創建這個文件。
看起來挺不錯的,但仍然有一點點美中不足就是,這個虛擬地址,必須有一個后綴名(而且推薦使用svc),對於一般的用戶而言,可能並不是特別友好。是否有辦法將這個地址進一步地簡化呢?
對於標准的SOAP服務來說,應該是沒有辦法了。但是如果是REST服務,倒是有另外一個方法來實現。請繼續閱讀下面的說明。
REST與路由規則
為了做演示,我將服務稍作修改,使得其成為所謂的RESTful的服務。請注意紅色粗體部分。
using System.ServiceModel; using System.ServiceModel.Web; namespace Web { [ServiceContract] public interface IHelloService { [OperationContract] [WebGet] string SayHello(); } public class HelloService : IHelloService { public string SayHello() { return "Hello,world"; } } }
然后我們還需要添加有關的配置文件設置(請注意粗體部分)
<?xml version="1.0"?> <!-- For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5" /> </system.web> <system.serviceModel> <services> <service name="Web.HelloService"> <endpoint contract="Web.IHelloService" binding="webHttpBinding"></endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="true"/> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior> <webHttp helpEnabled="true"></webHttp> </behavior> </endpointBehaviors> </behaviors> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"> <serviceActivations> <add service="Web.HelloService" relativeAddress="MyService.svc"/> </serviceActivations> </serviceHostingEnvironment> </system.serviceModel> </configuration>
為了使用我們自己想要的地址(虛擬地址)來訪問這個服務,我們可以結合路由規則來實現(這個也是WCF 4.0新增的特性)
將如下代碼添加到Global.asax文件中
using System; using System.ServiceModel.Activation; using System.Web.Routing; namespace Web { public class Global : System.Web.HttpApplication { private void RegisterRoutes() { WebServiceHostFactory factory = new WebServiceHostFactory(); RouteTable.Routes.Add(new ServiceRoute("HelloService", factory, typeof(HelloService))); } protected void Application_Start(object sender, EventArgs e) { RegisterRoutes(); } protected void Session_Start(object sender, EventArgs e) { } protected void Application_BeginRequest(object sender, EventArgs e) { } protected void Application_AuthenticateRequest(object sender, EventArgs e) { } protected void Application_Error(object sender, EventArgs e) { } protected void Session_End(object sender, EventArgs e) { } protected void Application_End(object sender, EventArgs e) { } } }
我們在這里是定義了一個路由規則,凡是請求HelloService這個虛擬路徑的(注意,沒有帶任何后綴),就路由到我們的服務。在瀏覽器中我們可以看到效果如下