前言
曾幾何時,微軟基于Web服務技術給出最流行的基于XML且以擴充名為.asmx結尾的Web Service,此服務在.NET Framework中風靡一時同時也被.NET業界同仁所青睐,幾年後在此基礎上又擴充成為了WCF,基于SOAP協定,基于WCF标準需要一些配置上的改變。現如今,大勢所趨我們隻需要HTTP協定以及更加優美的JSON格式,這時将不得不出現一個更加輕量級的Web服務技術。當然,Web Service和WCF雖然有其局限性但是其仍被許多企業所廣泛應用,說明一時半會還不會被淘汰,也有其存在的價值。
此時Web APi出現了,Web APi是一個僅僅隻支援HTTP協定而且非常強大的架構并且預設是JSON格式,我們和需要配置如endpoint、contarcts等繁瑣的配置的Web Service和WCF畫上了句号。Web APi基于ResetFul服務輕量而且強大,下面我們來看看Web APi是如何的強大以及輕量,它的優點和特點在哪裡?
優點
我們首先來看一張圖,如下

接下來我們一一解釋上述優點
Configuration
在WCF中我們需要endpoints和contracts,但是在Web APi中我們根本不需要這些設定(超簡單)。
預設是RESET
不像WCF,在WCF中一個服務對應的是從一個位址到一個實體檔案(簡言之:一個位址被映射到一個服務類或者是.svc檔案),當實體檔案移除位置或者删除其産生的影響可想而知,但是在Web APi中一個服務位址是一個RESET路由,并且該路由被映射到一個控制器上的方法(很靈活)。
Simpler Extensible Processing PipeLine
Web APi提供了一套高度可擴充的消息處理管道機制,其中如DelegateHandler以及Filer提供了請求和響應的機制。Handler允許我們在被激活的控制器以及控制器上方法進行自定義錯誤處理,同時它也能夠被配置來處理不同控制器上的路由。而Filter中包含了相應的類以及方法在控制器上的方法被調用之前和之後來允許我們運作一些代碼,例如:action filter、exception filter等等,與此同時這些過濾器對應的特性能夠修飾控制器上的方法,可以修飾單個或者全局皆可(高擴充)。
Abstraction With Route
給予Web服務開發者一個稍抽象的路由,但是開發者能夠看到并易懂這樣的一個實作,我們能夠映射任何一個URL到一個控制上的方法,換言之,這樣的抽象就不會具體對應到哪個檔案或者是哪個具體的接口,隻要URL對應一個有效的控制器方法我們就隻需要在對應的方法進行我們的實作即可(稍抽象路由)
特點
我們繼續以一張圖來概括
Convention-based CRUD Action
HTTP方法自動映射到控制器上對應的方法,并且通過URL裡所傳遞的參數Web APi也會自動比對,當然可能手動需要進行簡單的配置,其增删改查分别對應HTTP方法中的POST、GET、DELETE等。
Built-in Content Negotiation
我們知道在MVC上的控制器傳回什麼資料格式,如JSON或者XML需要我們去顯示指定傳回的類型,但是在Web APi上的控制器對應的方法隻需要傳回原始資料值即可,它會根據調用者的請求自動進行轉換為JSON或者XML。
Attribute Routing And Route Prefixs
路由特性以及路由字首都是非常明确的路由定義并且與我們控制器上的HTTP方法相關聯。
Route Constraints
對于特定的業務需求我們需要不同的路由來進行限制,比如類型,值的範圍等,Web APi中的路由限制是一個非常棒的特點。
CORS Support
這個跨域特點的支援真是讓我們大飽眼福,能夠完全進行js跨域請求,滿足所需。
Global Error Handling
在這個特點中,所有未被處理的錯誤機制都會被抓取到,通過通路的錯誤異常以及異常所在的上下文Web APi能夠支援多個異常處理記錄。
總結
從上可知,Web APi的強大以及靈活是WCF以及Web Service所無法比拟的,在Web服務技術中,Web APi的簡潔以及優雅已經成為最佳服務技術選擇。當然這也是站在Web Service以及WCF的肩膀上或者是時代的需求所發展出來的,我們隻需明白:腳有多大,就穿多大鞋。
啟動Session狀态
之前這個話題我是不知道的,在【嗨部落格】中有群友問才知道在Web APi中是不支援Session的,說的更加精準一點是預設沒有啟動Session,這裡就統一進行下學習,希望你有所收獲。 在Web APi中的Session不依賴于System.Web,如若要将Web APi運作在ASP.NET運作時,此時我們需要啟動Session,當我們隻要是在Web APi環境中就啟動APi該如何做?有兩種實作方式,請往下看。
Web APi全局啟動Session(一)
以下皆在Global.asax全局檔案中進行。
第一步(定義兩個變量)
private const string WebApiPrefix = "APi"; private static string WebApiExecutePath = string.Format("~/{0}", WebApiPrefix);
第二步(擷取目前請求的路徑)
private bool isWebAPiRequest() { return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(WebApiExecutePath); }
第三步(若請求Web APi則啟動Session)
protected void Application_PostAuthorizeRequest() { if (isWebAPiRequest()) { HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required); } }
第四步(測試代碼)
protected void Session_Start() { HttpContext.Current.Session.Add("xpy0928", "嗨-部落格"); var session_value = HttpContext.Current.Session["xpy0928"]; }
測試如下圖:
Web APi全局啟動Session(二)
之前我們在Web APi系列中講到過HttpControllerRouteHandler,此類中的GetHttpHandler方法傳回HttpControllerHandler的一個執行個體即HttpHandler,通過此HttpHandler是進入Web APi消息處理管道的入口點,我們可以使用在IHttpHandler上的Session實作IRquiressionstate接口即可。
第一步(啟動Session)
protected void Application_PostAuthorizeRequest() { HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required); }
第二步(自定義實作HttpControllerRouteHandler)
public class EnableSession_HttpControllerRouteHandler : HttpControllerRouteHandler { protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext) { return new EnableSession_ControllerHandler(requestContext.RouteData); } }
第三步(自定義實作HttpControllerHandler來擷取HttpHandler)
public class EnableSession_ControllerHandler : HttpControllerHandler, IRequiresSessionState { public EnableSession_ControllerHandler(RouteData routeData) : base(routeData) { } }
第四步(路由配置進行擷取自定義RouteHandler)
routes.MapHttpRoute( name: "DefaultAPi", routeTemplate: "api/{controller}/{id}", defaults: new { id = UrlParameter.Optional } ).RouteHandler = new EnableSession_HttpControllerRouteHandler();
第五步(在Web APi配置檔案中實作自定義HttpControllerRouteHandler)
public static void Register(HttpConfiguration config) { var httpControllerRouteHandler = typeof(HttpControllerRouteHandler).GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic); if (httpControllerRouteHandler != null) { httpControllerRouteHandler.SetValue(null, new Lazy<HttpControllerRouteHandler>(() => new EnableSession_HttpControllerRouteHandler(), true)); } config.MapHttpAttributeRoutes(); }
此時運作将出現如下錯誤:
【注意】解決方案:在Web API中屬性路由引起的HttpConfiguration.EnsureInitialized異常
第六步(測試代碼)
public void Get() { object context; if (Request.Properties.TryGetValue("MS_HttpContext", out context)) { var httpContext = context as HttpContextBase; if (httpContext != null && httpContext.Session != null) { var lastValue = httpContext.Session["xpy0928"] as int?; httpContext.Session["xpy0928"] = "部落格園"; var session_value = httpContext.Session["xpy0928"]; } } }
總結
以上兩種方法皆可在Web APi中啟動Session,你覺得那個簡單就按照對應的來。但我們需要注意一個問題:在Web APi中,Web APi是不依賴于HttpContext,也就是HttpContext.Current肯定是為null的,我們要通路Session或者其他對象需要使用Request對象中的屬性Properties來擷取你想要的值或者設定值。
所有的選擇不過是為了下一次選擇做準備