<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
首先建立一個Asp.Net MVC 4 Web應用程式(我這裡用的是Visual Studio 2012)。
在出來的模板中選擇Web API。點選確定後,就建立了一個空的WebAPI服務。
點選確定後,就建立了一個空的WebAPI服務。此時只有一個空專案,還沒有任何功能
在進行下一步之前,首先我們來看一下REST的基本操作模型,大致可以分為如下四種:
非常經典的CRUD模型。
在Web API中實現這樣一個的模型是非常簡單的,直接使用嚮導建一個Controller即可
在Web API中生成預設的ValuesController
預設的模板內容如下:
public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // GET api/values/5 public string Get(int id) { return "value"; } // POST api/values public void Post([FromBody]string value) { } // PUT api/values/5 public void Put(int id, [FromBody]string value) { } // DELETE api/values/5 public void Delete(int id) { } }
這其實已經幫我們實現了一個最基本的服務了,不過這個服務中只實現了Get,它支援如下兩種中方式的URL存取(其它的方式也能存取,但沒有具體的效果):
api/values 存取所有的Value列表
api/values/{id} 根據ID存取Value
按Ctrl + F5中執行,在瀏覽器中輸入相應的地址即可看到結果
下面我們要做的就是完善它,實現一個簡單的查詢功能,這裡我參照了微軟官方的一個例子:
public class ProductsController : ApiController { Product[] products = new Product[] { new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } }; public IEnumerable Get() { return products; } public IHttpActionResult Get(int id) { var product = products.FirstOrDefault((p) => p.Id == id); if (product == null) { return NotFound(); } return Ok(product); } } public class Product { public int Id { get; set; } public string Name { get; set; } public string Category { get; set; } public decimal Price { get; set; } }
此時,我們就可以在瀏覽器中看到結果了(由於Controller改名字了,此時的地址就變成了api/products)
到此為止,一個基於Asp.net Web API的 簡單的REST Web服務就構建完成了,由於篇幅所限,這裡就不做更多的介紹了,跟多資訊可以參看微軟官方檔案:Getting Started with ASP.NET Web API 2。
備註:WebAPI升級到 WebAPI 2如下命令更新web Api:
Install-Package Microsoft.AspNet.WebApi
REST並沒有像傳統的RPC服務那樣顯式指定了伺服器函數的存取路徑,而是將URL根據一定的規則對映為服務函數入口,這個規則就稱之為路由。Asp.Net WebAPI的路由方式和Asp.Net MVC是相同的,它支援兩種路由方式,傳統的路由對映和特性路由。 路由規則WebApiConfig.cs中定義。
它的預設內容如下:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API configuration and services // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
它預設註冊了兩種路由規則,第一行註冊的是特性路由,第二行註冊的則是傳統的對映路由。預設情況下,由於我們沒有編寫特性路由規則,則是按照傳統的Controller方式對映路由。
關於路由規則,MSDN檔案ASP.NET 路由介紹得非常詳細,但由於其介紹得太詳細了,反而不容易得其門而入,這裡我只拿預設的路由規則來簡單但的介紹一下我的理解,它的uri格式是這樣的"api/{controller}/{id}",其中id是可選的。拿前文的例子來說吧,
另外,這裡也有幾個常用的衍生規則:
當我們使用帶引數的版本時候,也有幾個需要注意的地方:
預設的規則雖然大多數的時候還是比較方便的,但是很多時候我們需要手動指定個性化的路由規則。例如,我們可以自定義一個按名稱來查詢的url:api/products/name=xxx。這個時候則可以用特性路由快速的實現了:
[Route("api/{controller}/name={name}")] public IHttpActionResult GetByName(string name)
關於特性路由,MSDN原文Attribute Routing in ASP.NET MVC 5介紹得非常詳細。
Asp.Net WebAPI服務函數的返回值主要可以分為void、普通物件、HttpResponseMessag、IHttpActionResult e四種,本文這裡簡單的介紹一下它們的區別。
返回void一般常用於Put和Delete函數。
public void Delete(int id) { }
當服務函數執行完成後,伺服器端並不是啥都不幹直接把使用者端給斷掉,而是傳送一個標準的204 (No Content)的Http應答給使用者端。
HTTP/1.1 204 No Content Cache-Control: no-cache Pragma: no-cache Expires: -1 Server: Microsoft-IIS/8.0 X-AspNet-Version: 4.0.30319 X-SourceFiles: =?UTF-8?B?Zjpc5paH5qGjXHZpc3VhbCBzdHVkaW8gMjAxM1xQcm9qZWN0c1xXZWJBcHBsaWNhdGlvbjFcV2ViQXBwbGljYXRpb24xXGFwaVx2YWx1ZXNcMQ==?= X-Powered-By: ASP.NET Date: Fri, 02 May 2014 13:32:07 GMT
返回普通物件時,伺服器將返回的物件序列化後(預設是json),通過Http應答返回給使用者端。例如,
public class ValuesController : ApiController { public string Get() { return "hello"; } }
此時的返回結果是:
HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Type: application/json; charset=utf-8 Expires: -1 Server: Microsoft-IIS/8.0 X-AspNet-Version: 4.0.30319 X-SourceFiles: =?UTF-8?B?Zjpc5paH5qGjXHZpc3VhbCBzdHVkaW8gMjAxM1xQcm9qZWN0c1xXZWJBcHBsaWNhdGlvbjFcV2ViQXBwbGljYXRpb24xXGFwaVx2YWx1ZXM=?= X-Powered-By: ASP.NET Date: Fri, 02 May 2014 12:54:18 GMT Content-Length: 7 "hello"
非同步返回普通物件:
WebAPI也是支援非同步返回物件的:
public async Task<string> Get() { await Task.Delay(100); return "hello"; }
非同步返回的時候,伺服器非同步等待函數執行完成後再將返回值返回給物件。由於這個過程對於使用者端來說是透明的,這裡就不列舉報文了。
HttpResponseMessage是標準Http應答了,此時伺服器並不做任何處理,直接將HttpResponseMessage傳送給使用者端。
public HttpResponseMessage Get() { var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StringContent("hello", Encoding.UTF8); return response; }
此時的返回結果如下:
HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Length: 5 Content-Type: text/plain; charset=utf-8 Expires: -1 Server: Microsoft-IIS/8.0 X-AspNet-Version: 4.0.30319 X-SourceFiles: =?UTF-8?B?Zjpc5paH5qGjXHZpc3VhbCBzdHVkaW8gMjAxM1xQcm9qZWN0c1xXZWJBcHBsaWNhdGlvbjFcV2ViQXBwbGljYXRpb24xXGFwaVx2YWx1ZXM=?= X-Powered-By: ASP.NET Date: Fri, 02 May 2014 13:09:57 GMT hello
可以看到,這裡返回的content-type仍然是原始定義的text型別,而不是json。要實現想上面的例子所示的結果,則需要將Get函數改寫為如下形式
public HttpResponseMessage Get() { return Request.CreateResponse(HttpStatusCode.OK, "hello"); }
IHttpActionResult是Web API 2 中引入的一個介面,它的定義如下:
public interface IHttpActionResult { Task ExecuteAsync(CancellationToken cancellationToken); }
從它的定義可以看出,IHttpActionResult是HttpResponseMessage的一個工廠類,最終還是用於構建HttpResponseMessage返回,由於它可以取消,因而可以實現更為強大的返回功能(如流傳輸)。當服務函數返回IHttpActionResult物件時,伺服器執行該物件的ExecuteAsync函數,並非同步等待至函數完成後,獲取其返回值HttpResponseMessage輸出給使用者端。
IHttpActionResult是WebAPI中推薦的標準返回值,ApiController類中也提供了不少標準的工廠函數方便我們快速構建它們,如BadRequest,Conflict,Ok,NotFound等,一個簡單的範例如下:
public IHttpActionResult Get(int id) { var product = products.FirstOrDefault((p) => p.Id == id); if (product == null) { return NotFound(); } return Ok(product); }
WebAPI把引數分成了簡單型別和複雜型別:
例如,對於如下函數
HttpResponseMessage Put(int id, Product item)
其id預設從url中獲取,其item預設從正文中獲取。
我們可以使用 [FromUri] 標記強制從URI中繫結引數,例如
public class GeoPoint { public double Latitude { get; set; } public double Longitude { get; set; } } public ValuesController : ApiController { public HttpResponseMessage Get( [FromUri] GeoPoint location) { ... } }
這樣,Get引數就是從URI中獲取了讀取GeoPoint物件。需要注意的是,此時我們必須將GeoPoint物件的屬性在URI中傳入: http://localhost/api/values/?Latitude=47.678558&Longitude=-122.130989 。
這種預設的序列化方式比較冗長,我們也可以自定義反序列化格式為類似這樣的形式:http://localhost/api/values/?location=47.678558,-122.130989,具體方法請參看參考檔案 Type Converters 的一節。
同樣,我們可以使用 [FromBody] 標記強制從正文中繫結引數,例如
public HttpResponseMessage Post( [FromBody] string name)
將強制從FormData等非URL引數中讀取資料
前面介紹的方式中,只能從URI中繫結一個引數,雖然可以通過傳入複雜型別解決多引數的問題,但很多時候不如在URI中來得直接。此時,我們則可以使用前面介紹的特性路由來實現多參的繫結,例如:
[Route("api/{controller}/{year}/{month}/{day}")] public string Get(int year, int month, int day) { return string.Join(",", year, month, day); }
參考檔案: http://www.asp.net/web-api/overview/formats-and-model-binding
WebAPI是標準的Http協定,支援Http協定的使用者端(如瀏覽器)都可以存取。但是,有的時候我們如果想在自己的程式中使用WebAPI時,此時就要實現自己的使用者端了。
我之前介紹過在.Net 4.5中新增的HttpClient庫,它對Http操作實現了非常好的封裝。我們可以通過它實現Http存取,例如,我們對前文所示的API進行一次Post操作:
// POST: api/Values public void Post(Product value) { }
首先對HttpClient進行一些初始化操作:
var client = new HttpClient(); client.BaseAddress = new Uri("http://localhost:1282/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
這裡主要進行了兩部操作:1. 定義了預設的基地址,減少後續的URL長度,2. 定義了預設的接受的資料型別為Json。
下一步就要開始對Product物件的內容編碼,預設是xml或json,這裡我選擇相對簡單的json:
var product = new Product() { Id = 1, Name = "food" }; var content = Newtonsoft.Json.JsonConvert.SerializeObject(product); var httpContent = new StringContent(content, Encoding.UTF8); httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json") { CharSet = "utf-8" }; await httpContent.LoadIntoBufferAsync(); var rsp = await client.PostAsync("api/values", httpContent);
從上面的程式碼可以看出,由於WebAPI不像WCF那樣能自動生成使用者端程式碼,需要我們自己封裝物件,上面光封裝物件就用了四行程式碼,對於不熟悉HttpClient朋友來說還是比較容易出錯的。因此微軟提供了一系列擴充套件函數方便我們簡化這一過程。
在Nuget中安裝WebApi.Client庫
這個庫安裝後會在參照中增加一個System.Net.Http.Formatting的程式集,它主要提供了一系列擴充套件函數(其實裝這個庫順帶也會把HttpClient和Json.Net一併安上),現在上面的程式碼就可以簡化如下了:
var product = new Product() { Id = 1, Name = "food" }; var rsp = await client.PostAsJsonAsync("api/values", product);
除了PostAsJsonAsync這個擴充套件函數外,還提供了PostAsXmlAsync這種以XML傳輸的方式。同樣,Put也有PutAsJsonAsync和PutAsXmlAsync的擴充套件版本。對於Get,雖然也提供了擴充套件函數,但是使用的方式稍有不同:
var rsp = await client.GetAsync("api/values/1"); rsp.EnsureSuccessStatusCode(); var product = await rsp.Content.ReadAsAsync();
對於Delete,卻沒有提供擴充套件函數,可能是官方認為Delete直接在URL中就傳ID就夠用了,沒必要在Request中封裝訊息了吧。
限於篇幅,今天就介紹到這裡了,更多內容的可以參看官方檔案:http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client
Asp.Net WebAPI生成的是一個程式集,並不是獨立的程序,因此,要執行的時候必須將其承載在相應的宿主上,一般比較常見的是IIS承載。
很多時候,我們為了簡化部署或者功能整合,需要將其承載到獨立的程序上,這種方式一般稱之為Self-Host,本文就簡單的介紹一下WebAPI的SefHost方法。
首先在Nuget上安裝Microsoft.AspNet.WebApi.SelfHost庫。
附上我們的WebAPI控制器
public class ValuesController : ApiController { public IEnumerable<string> Get() { return new string[] { "111", "222" }; } }
接下來的工作就是啟動我們的伺服器了。
class Program { static void Main(string[] args) { //Assembly.Load("WebApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); //載入外部程式集 var config = new HttpSelfHostConfiguration("http://localhost:8080"); config.Routes.MapHttpRoute( "API Default", "api/{controller}/{id}", new { id = RouteParameter.Optional }); using (var server = new HttpSelfHostServer(config)) { server.OpenAsync().Wait(); Console.WriteLine("Press Enter to quit."); Console.ReadLine(); } } }
從上面的程式碼可以看出,組態檔和Asp.Net程式中基本上是一樣的,如果是直接用Asp.Net專案中生成的DLL的話,我們也可以直接用其WebApiConfig.Register的方法來進行設定的(需要像第一行注掉的那樣使用Assembly.Load載入程式集)。下面一段就是啟動伺服器了,更多內容可以參看MSDN檔案:http://www.asp.net/web-api/overview/hosting-aspnet-web-api/self-host-a-web-api
值得一提的是,SelfHost是在一個獨立程序中啟動了Http服務,也可以是說,它是一個mini版的Http伺服器,我之前介紹過通過HttpListener實現簡單的Http服務,到了現在,用WebAPI的SelfHost方式是可以更加快捷的實現擴充套件性更好的Mini Http伺服器的,當我們需要一個簡單的Http服務的時候,可以使用這種方式。
除了這種方式外,微軟更加推薦用功能更加強大的OWIN來承載WebAPI服務。
另外,除了IIS、SelfHost等方式外,雲時代釋出到Windows Azure也是非常便捷的,這裡就不做多少介紹了,詳細內容請參看MSDN檔案:http://www.asp.net/web-api/overview/hosting-aspnet-web-api 。
由於WebAPI本身是基於HTTP協定的,在開發過程中,我們可以使用瀏覽器或Fiddler等HTTP工具輔助開發。與此同時,微軟也提供了一些工具方便我們偵錯,使得開發更加簡單快捷,本文就簡單的介紹一下這幾個工具。
通過幫助檔案,我們可以非常直觀的看到控制器生成了那些路由,通過這些介面檔案可以非常方便的指導使用者端開發。
要開啟幫助檔案,可以參看這篇文章: http://www.asp.net/web-api/overview/creating-web-apis/creating-api-help-pages
當我們應用了大量的路由規則和自定義路由的時候,有的時候,就會出現一條路由具體走的那條規則的情況,這個時候,則可以通過路由偵錯程式來幫助我們進行分析和定位:
要啟用路由偵錯程式,可以參看如下地址:http://blogs.msdn.com/b/webdev/archive/2013/04/04/debugging-asp-net-web-api-with-route-debugger.aspx
執行過程跟蹤工具則可以非常直觀的列印出其互動過程,可以非常方便的檢視我們是否進行了正確的輸入和獲得了相應的輸出。
要啟用執行過程跟蹤,可以參考這個地址:http://www.asp.net/web-api/overview/testing-and-debugging/tracing-in-aspnet-web-api
不過它將執行過程列印在OutPut視窗中了,有的時候不是很方便,可以將其修改一下,用SignalR列印在網頁或第三方使用者端上,加一些輸出資訊高亮的話,則更加方便一些。
到此這篇關於使用ASP.Net WebAPI構建REST服務的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45