生活需要自己慢慢去體驗和思考,對於知識也是如此。匆匆忙忙的生活,讓人不知道自己一天到晚都在干些什麼,似乎每天都在忙,但又好似不知道自己到底在忙些什麼。不過也無所謂,只要我們知道最後想要什麼就行。不管怎麼樣,我們還是得學習,讓自己不斷的向前,這樣才可以漸漸看到自己的追求,發發感歎,誰讓樓主以前是寫小說的呢(想看樓主以前的小說可以私聊我,以前絕對貨真價實的文藝青年,可惜現在已經是屌絲了。)
不扯淡,還是來聊正經事,什麼正經事勒?對於程序員來說,當然代碼才是正經事了。
在我們的項目開發中,很多時候需要使用到多系統的數據交互,以及一些功能的分布式開發。在.NET的體系中的分布式技術主要有webservice,.net remoting,MSMQ,WCF等等,但是今天介紹的是Asp.Net WebApi,對於Asp.Net WebApi技術,估計很多人都不會陌生,或者經常使用,因為對於其他的分布式技術的問題,在使用的時候會比較的繁瑣,但是Asp.Net WebApi可能會簡便和快捷很多。下面具體介紹一下Asp.Net WebApi技術。
ASP.NET Web API是在.NET Framework之上構建的Web的API的框架,ASP.NET Web API是一個編程接口,用於操作可通過標准HTTP方法和標頭訪問的系統,ASP.NET Web API需要基於.NET 3.5或更高版本才可以進行開發。我們在學習ASP.NET Web API時,需要對HTTP協議、web知識有一個比較深入的認識,這樣在學習ASP.NET Web API時會比較快速的上手和應用。這裡就不介紹HTTP協議和Web相關的基礎知識,需要了解的可以自行百度搜索學習。
ASP.NET Web API可提供各種HTTP客戶端使用,可以使用web基礎設施提供的服務。
(1).可供多種客戶端使用。
(2).支持標准的HTTP方法。
(3).支持浏覽器友好的格式。(支持浏覽器以及任何其它HTTP客戶端容易支持的格式,例如json,xml等數據格式)
(4).支持浏覽器友好的認證方式。
(1).System.Net.Http:提供核心HTTP編程模型。
(2).System.AspNet.WebApi:提供在ASP.NET中安裝和托管所需的安裝的所有軟件包的一個引用。
(3).System.AspNet.WebApi.Core:包含核心WebApi編程模型和運行時組件。
(4).System.AspNet.WebApi.Client:包含核心.NET HTTP客戶端庫的擴展。
(5).System.AspNet.WebApi.WebHost:包含在ASP.NET運行時中托管WebApi所需的全部運行時組件。
對於ASP.NET Web API的簡單demo、安全認證、異常處理、內容協商、寄宿方式、錯誤處理等等,在這裡就不再過於介紹,如果有時間博主會單獨講解這些內容。
對於ASP.NET Web API路由的介紹會比較簡單,因為對於熟悉asp.net mvc的人來說不是什麼難事,而且本次博文的重點並不是在這裡,所以在這裡只會做一個簡單的介紹。ASP.NET WebAPI使用HTTP方法,而不是URI路徑,以此來選擇動作。還可以使用MVC樣式路由的WebAPI。
在ASP.NET Web API中,一個控制器是處理HTTP請求的類。控制器的公共方法被稱為動作方法或簡單的動作。當Web API框架接收到一個請求,它請求路由到一個動作。要確定調用哪個動作,框架使用的路由表。如下代碼:
routes.MapHttpRoute( name: "API Default", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );
我們在設置WebAPI路由時,已盡量注意與AspNet Mvc的路由發生沖突,這一點在ASP.NET Web API中做了一個防范。
ASP.NET Web API的路由運行機制如下:
(1).找到控制器,網絡API將“控制器”的值 {}控制變量。
(2).查找的動作,網絡API著眼於HTTP方法,然後尋找一個動作名稱以該HTTP方法名。例如,用GET請求,WebAPI查找與“獲取...”,例如“GetContact”或“GetAllContacts”開頭的動作。該公約只適用於GET,POST,PUT和DELETE方法。您可以通過使用控制器上的屬性啟用其他HTTP方法。
(3).在路由模板其他占位符變量,諸如{ID},被映射到動作的參數。
對於ASP.NET Web API的路由機制就講解這麼多,更多的內容大家可以自己去了解。
在我們的asp.net webapi項目中,在頂層目錄App_Start下,有一個WebApiConfig類,該類只包含一個方法Register,由Global.asax中的Application_Start方法調用代碼,如下代碼:
GlobalConfiguration.Configure(WebApiConfig.Register);
路由的映射方法只是一個擴展方法,如果需要了解“擴展方法”的相關知識,可以閱讀以下:http://www.cnblogs.com/pengze0902/p/6110094.html,在這裡就做介紹了,創建一個路由實例,並把這個實例添加到與宿主相關的路由集合之中。
現在這裡著重介紹一下ApiController類。
ApiController是ValuesController類的父類,是整個ASP.NET Web API的核心類,繼承該類可以用來創建ASP.NET Web API控制器。ApiController類中的公共靜態(在Visual Basic中共享)成員是線程安全的,任何實例成員都不能保證是線程安全的。下面介紹一下ApiController在ASP.NET Web API中所承擔的任務如下:
(1).選擇和運行控制器類上的一個操作方法。
(2).將HTTP請求消息的各元素轉換成控制器操作方法的參數,並將操作方法的返回值轉換為有效的HTTP響應正文。(HTTP響應body的數據格式可以客戶端和服務器進行協商,默認為json格式,對於json格式的好處,在這裡就不做介紹,但是個人覺得json格式應該會成為以後數據格式的重心。)
(3).運行各種篩選器,這些篩選器可以是為操作方法或控制器配置,也可以是全局的。
(4).為控制器類的操作方法提供適當的上下文狀態。
以上是ApiController類的作用的簡單介紹,下面我們具體看一下實現代碼。
首先,我們先來預覽一下ApiController類的方法和屬性:
ActionContext:獲取操作上下文;
Configuration和ControllerContext:獲取當前 ApiController 的 HttpConfiguration對象;
ModelState:在模型綁定過程之後獲取模型狀態;
Request:獲取或設置當前 ApiController 的 HttpRequestMessage;
RequestContext: 獲取請求上下文;
Url:用於生成指向其他 API 的 URL;
User:返回與此請求關聯的當前主體;
ExecuteAsync(): 異步執行單個 HTTP 操作,該方法為虛方法,可在子類中重寫;
Validate<TEntity>():驗證給定實體並使用空前綴將驗證錯誤添加到模型狀態;
Initialize():使用指定的 controllerContext 初始化 System.Web.Http.ApiController 實例;
BadRequest():創建具有指定的InvalidModelStateResult模型狀態。
Created():創建一個CreatedNegotiatedContentResult`1(201表示已創建)具有指定的值。
Redirect():創建具有指定值的重定向結果(302 Found)。
ResponseMessage():創建具有指定響應的ResponseMessageResult。
ApiController類實現了IHttpController和IDisposable接口。在ASP.NET Web API中如果需要創建控制器,只需要實現IHttpController接口即可,我們看一下IHttpController接口的實現代碼:
//表示 HTTP 控制器 public interface IHttpController { // 執行用於同步的控制器。 //參數:controllerContext:測試控制器的當前上下文。cancellationToken:取消操作的通知。 //返回結果:控制器。 Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken); }
可以看到該接口只有一個方法ExecuteAsync(),該方法為一個異步方法,HttpControllerContext表示一個HTTP請求對象,CancellationToken表示一個傳遞一個消息,為HTTP操作分配的取消令牌,Task<HttpResponseMessage>可以看出該方法返回一個異步的HTTP對象。我們看一下ApiController類中隊該類的實現代碼:
/// <summary> /// 異步執行單個 HTTP 操作。 /// </summary> /// <returns> /// 新啟動的任務。 /// </returns> /// <param name="controllerContext">單個 HTTP 操作的控制器上下文。</param><param name="cancellationToken">為 HTTP 操作分配的取消標記。</param> public virtual Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) { if (this._initialized) throw Error.InvalidOperation(SRResources.CannotSupportSingletonInstance, new object[2] { (object) typeof (ApiController).Name, (object) typeof (IHttpControllerActivator).Name }); this.Initialize(controllerContext); if (this.Request != null) HttpRequestMessageExtensions.RegisterForDispose(this.Request, (IDisposable) this); ServicesContainer services = controllerContext.ControllerDescriptor.Configuration.Services;
//根據HTTP請求內容選擇動作 HttpActionDescriptor actionDescriptor = ServicesExtensions.GetActionSelector(services).SelectAction(controllerContext); this.ActionContext.ActionDescriptor = actionDescriptor; if (this.Request != null) HttpRequestMessageExtensions.SetActionDescriptor(this.Request, actionDescriptor); FilterGrouping filterGrouping = actionDescriptor.GetFilterGrouping();
//獲取動作過濾器 IActionFilter[] actionFilters = filterGrouping.ActionFilters;
//獲取授權過濾器 IAuthenticationFilter[] authenticationFilters = filterGrouping.AuthenticationFilters; IAuthorizationFilter[] authorizationFilters = filterGrouping.AuthorizationFilters;
//獲取異常過濾器 IExceptionFilter[] exceptionFilters = filterGrouping.ExceptionFilters; IHttpActionResult innerResult = (IHttpActionResult) new ActionFilterResult(actionDescriptor.ActionBinding, this.ActionContext, services, actionFilters); if (authorizationFilters.Length > 0) innerResult = (IHttpActionResult) new AuthorizationFilterResult(this.ActionContext, authorizationFilters, innerResult); if (authenticationFilters.Length > 0) innerResult = (IHttpActionResult) new AuthenticationFilterResult(this.ActionContext, this, authenticationFilters, innerResult); if (exceptionFilters.Length > 0) { IExceptionLogger logger = ExceptionServices.GetLogger(services); IExceptionHandler handler = ExceptionServices.GetHandler(services); innerResult = (IHttpActionResult) new ExceptionFilterResult(this.ActionContext, exceptionFilters, logger, handler, innerResult); } return innerResult.ExecuteAsync(cancellationToken); }
由以上的實現代碼可以看出,含有三個類型的過濾器,分別是 IActionFilter、IAuthenticationFilter、IExceptionFilter,該方法在獲取到消息請求後,初始化消息和請求,調用 HttpRequestMessageExtensions.RegisterForDispose(this.Request, (IDisposable) this)該方法進行注冊,該方法會對請求信息進行過濾操作。
我們接下來看一下Request和RequestContext屬性的具體代碼:
/// <summary> /// 獲取或設置當前ApiController的 HttpRequestMessage。 /// </summary> /// <returns> /// 當前ApiController的 HttpRequestMessage。 /// </returns> public HttpRequestMessage Request { get { return this.ControllerContext.Request; } set { if (value == null) throw Error.PropertyNull(); HttpRequestContext requestContext1 = HttpRequestMessageExtensions.GetRequestContext(value); HttpRequestContext requestContext2 = this.RequestContext; if (requestContext1 != null && requestContext1 != requestContext2) throw new InvalidOperationException(SRResources.RequestContextConflict); this.ControllerContext.Request = value; HttpRequestMessageExtensions.SetRequestContext(value, requestContext2); RequestBackedHttpRequestContext httpRequestContext = requestContext2 as RequestBackedHttpRequestContext; if (httpRequestContext == null) return; httpRequestContext.Request = value; } } /// <summary> /// 獲取請求上下文。 /// </summary> /// <returns> /// 請求上下文。 /// </returns> public HttpRequestContext RequestContext { get { return this.ControllerContext.RequestContext; } set { if (value == null) throw Error.PropertyNull(); HttpRequestContext requestContext1 = this.ControllerContext.RequestContext; HttpRequestMessage request = this.Request; if (request != null) { HttpRequestContext requestContext2 = HttpRequestMessageExtensions.GetRequestContext(request); if (requestContext2 != null && requestContext2 != requestContext1 && requestContext2 != value) throw new InvalidOperationException(SRResources.RequestContextConflict); HttpRequestMessageExtensions.SetRequestContext(request, value); } this.ControllerContext.RequestContext = value; } }
Request和RequestContext屬性分別用於設置和獲取HttpRequestMessage對象和RequestContext對象,
ASP.NET Web API除了可以根據HTTP方法來選擇操作方法,還可以根據請求的其他元素選擇操作方法。ASP.NET Web API框架支持從請求元素到操作方法參數的綁定。對於HTTP響應值轉換成適當的HTTP響應消息正文。
以上是對ASP.NET Web API背景和使用方法,以及對ASP.NET Web API核心對象的簡要介紹,下篇會主要介紹HttpRequestMessage、HttpResponseMessage、HttpClient等三個對象的解析。如果文中有不足和講解錯誤之處,還望大家多多指正。