進擊的 ASP.NET Web API 2 巨人 – 打造支援各種裝置及平台的服務
作者: 陳傳興(Bruce,微軟最有價值專家)
ASP.NET Web API隨著ASP.NET MVC 4一起發行立即造成轟動,它取其WCF Web API與ASP.NET MVC精華於一身,又去除WCF本身較繁瑣與延伸配置的問題,更只因專注在提供HTTP Service,使得ASP.NET Web API服務開發人員可快速開發出自身使用或對外公開的Web API。前端應用程式只要能發出HTTP的URI請求(例如:https://domain/api/products)向Web API請求服務即可取得如JSON或XML或自訂的資料來源(Data Source)並立即使用於應用程式之內。
ASP.NET Web API 2主要有二部分的改進,一是功能提升,例如:Attribute Routing、OData改進、可攜式ASP.NET Web API Client、IHttpActionResult,另一方是安全性功能提升,例如:CORS、Authentication filters。另外,OWIN讓ASP.NET Web API能運作於相容OWIN的託管環境,而不再非IIS不可。
Attribute routing
Web API現在支援「屬性路由」,這是由https://attributerouting.net作者Tim McCall所捐獻,讓我們謝謝他。
屬性路由讓開發人員可以指定屬性的方式來設置路由至Controller或Action,例如以下針對連絡Action方法的設置:
[GET("contacts")]
public IEnumerable<Contact> Get() {}
[GET("contact/{id}")]
public Contact Get(int id) {}
[GET("contactOrDefault/{id=1}")]
public Contact GetWithDefault(int id) {}
[GET("contactRange/{id:range(1,3)}")]
public Contact GetWithRange(int id) {}
屬性路由也提供方便的語法讓開發人員指定選擇性參數(例如:people/{name ? })、預設值(people/{name=Bruce})、路由限制等。
使用屬性路由,開發人員可以簡單的在單一個Controller中就定義出層級關係,例如:
public class MoviesController : ApiController
{
[GET("movies")]
public IEnumerable<Movie> Get() { }
[GET("actors/{actorId}/movies")]
public IEnumerable<Movie> GetByActor(int actorId) { }
[GET("directors/{directorId}/movies")]
public IEnumerable<Movie> GetByDirector(int directorId) { }
}
OData改善
ASP.NET Web API 的OData支援更完整$select、$expand、$value。另外,也能使用$batch來做為“請求批次處理”的變更集合的處理。
擴充性方面改善了OData格式器,使開發人員可增加Atom的metadata項目,支援命名資料流(named stream)和媒體連結項目(media link entries),加入執行個體註解(instance annotations)和自訂連結產生(customize link generation)。
Request batching
請求批次(request batching)可以多個操作組合成單一個HTTP POST請求負載(request payload),以減少網路流量,提供更順暢更少交握的使用者介面。
ASP.NET Web API 2現在支援從OData協定提供的$batch端點服務,在一個MIME的multipart請求裡包裝進去多個請求,或使用自訂的批次格式。開發人員可以控制請求或執行的順序,或是任意順序。
啟用請求批次很簡單,只需要加入批次處理常式(batching handler)到Web API的路由組態中即可,例如:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpBatchRoute(
routeName: "WebApiBatch",
routeTemplate: "api/batch",
batchHandler: new DefaultHttpBatchHandler(GlobalConfiguration.DefaultServer)
);
}
}
注意,它是定義在MapHttpBatchRoute擴充方法中。
可攜式ASP.NET Web API Client
圖一
現在,你可以在可攜式類別(portable class)中去使用ASP.NET Web API Client,讓Windows Store和Windows Phone 8應用程式去呼叫使用,以方便存取Web API。你也可以建立可攜式格式器,在用戶端和伺服器端之間共用。
改善測試能力
API Controller的單元測試現在更容易,簡單的實例化API Controller的請求訊息和組態,然後調用你想測試的操作方法。當你Action方法執行連結產生情況時,現在,你可以輕鬆地Url Helper類別[1]來模擬處理。
IHttpActionResult
開發人員現在可以實作IHttpActionResult介面以封裝ASP.NET Web API的Action方法回傳結果。
IHttpActionResult 介面只有一個方法:
namespace System.Web.Http
{
public interface IHttpActionResult
{
Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken);
}
}
IHttpActionResult並不是創新的東西,它只是簡單的拿來建立熟悉的 HttpResponseMessage,但它是非常有用的。它是一個有用的 HttpResponseMessage工廠,通過實作介面,你可以提供如何建構新回應方法的說明。
Cross Origin Request Sharing
感謝另一個作者Brock Allen[2]的捐獻,現在ASP.NET可以完全支援Cross Origin Request Sharing(CORS)。這會無縫的整合在ASP.NET Web API之中,以支援使用CORS包含在預先請求前的自動處理。
Cross-origin resource sharing (跨來源資源分享,CORS)是W3C[3]提案的技術標準,定義伺服器與用瀏覽器在跨來源(即cross domain,跨網域)呼叫時的互動方式。CORS標準允許網頁發出跨網域的AJAX請求,讓實作了同源策略(same-origin)的瀏覽器在安全條件下去呼叫進行有限制的跨網域AJAX請求。
測試跨網域的AJAX請求
透過Visual Studio 2013新增一個MVC 5與一個Web API 2專案,在MVC 5專案安裝Web API測試套件:
Install-Package WebApiTestClient
修改MVC 5專案的Api.cshtml(~\Areas\HelpPage\Views\Help)檔案最後面:
修改前:
@section Scripts {
<link type="text/css" href="~/Areas/HelpPage/HelpPage.css" rel="stylesheet" />
}
修改後:
@Html.DisplayForModel("TestClientDialogs")
@section Scripts {
<link type="text/css" href="~/Areas/HelpPage/HelpPage.css" rel="stylesheet" />
@Html.DisplayForModel("TestClientReferences")
}
現在筆者專案配置如下:
« MVC 5專案:https://localhost:13466/
« Web API 2專案:https://localhost:13107/
透過Test Client當請求端向Web API專案請求服務,但由於兩個專案的Port不一樣,會當成跨網域的AJAX請求:
圖二
圖三
CORS透過設定HTTP Header(標頭)設置那些網域的網站可以跨網域存取,目前W3C定義九個Response Header(回應標頭)可以設置:
Response Header |
說明 |
Access-Control-Allow-Origin |
指示是否基於共享資源透過回傳來源請求標頭、“*”或“null”在回應裡。 |
Access-Control-Allow-Credentials |
指示當省略憑證標誌(Credentials flag)未設置時,是否公開請求的回應。當檢查請求(preflight request)的回應一部分,它表明實際的請求可以包含用戶端憑證。 |
Access-Control-Expose-Headers |
指示那些標頭是安全公開在CORS API規範的API。 |
Access-Control-Max-Age |
指示檢查請求可以快取多久時間在快取結果裡。 |
Access-Control-Allow-Methods |
指示實際請求期間,可以使用那些方法做為請求回應的一部分。 |
Access-Control-Allow-Headers |
指示實際請求期間,可以使用那些標頭名稱做為請求回應的一部分。 |
Origin |
指示跨來源請求或檢查請求來自於。 |
Access-Control-Request-Method |
指示那種方法在實際請求中做為檢查請求的一部分。 |
Access-Control-Request-Headers |
指示那種標頭在實際請求中做為檢查請求的一部分。 |
例如,我們可以設置以下CORS標頭:
Access-Control-Allow-Origin: https://www.microsoft.com
Access-Control-Allow-Methods: PUT, DELETE
這表示,除了網站本身以外,僅允許www.microsoft.com網域進行跨網域的AJAX請求且只允許PUT和DELETE方法的請求。允許的網域可以設定多組,也能設定為“*”代表不設限。
啟用CORS
要在ASP.NET Web API啟用CORS功能,只需要參NuGet下載相關套件即可:
在WebApiConfig先引用必須要命名空間:
using System.Web.Http.Cors;
然後於Register方法裡啟用Cors功能:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.EnableSystemDiagnosticsTracing();
config.EnableCors();
}
}
依config.EnableCors方法設置不同,Cors的影響範圍可能是全域性、Controller或Action。如果全部設置,預設由內而外執行,即:
- Action
- Controller
- Global
[EnableCors("*", "*", "*")]
public class ValuesController : ApiController
{
public IEnumerable<string> Get() {}
public string Get(int id) {}
public void Post([FromBody]string value) {}
public void Put(int id, [FromBody]string value) {}
[DisableCors]
public void Delete(int id) {} {}
}
在ValuesController類別設置EnableCors屬性後,ValuesController類別裡Action方法即可被跨網域存取,另外可設DisableCors屬性來排除特定Controller或Action方法不可被跨網域存取。
圖四
認證過濾器
認證過濾器(Authentication filters)是ASP.NET Web API一個新類型的過濾器,在ASP.NET Web API管線中會優先處理認證過濾器,並且可以在每一Action方法或每一Controller或全域設置至全部Controller的認證邏輯。認證過濾器會在請求中處理使用者憑證(credentials)並提供相對應的主體(principal)。認證過濾器還可以在未經授權的請求中加入驗證挑戰(authentication challenge)至回應裡。
過濾器覆寫
現在,透過指定覆寫過濾器(override filter),你可以把覆寫過濾器用於給定的Action方法或Conotroller,覆寫過濾器應該指定一組不應執行的範圍(Action或Controller)的過濾器型別。這樣允許開發人員組態過濾器並套用至全域配置,然後排除特定的全域過濾器套用至特定的Action或Controller上。
OWIN的支援與整合
ASP.NET Web API現在完全支援OWIN[4](Open Web Interface for .NET),並且可運作於任何相容於OWIN的主機(Host)。
Open Web Interface for .NET(OWIN)定義一個介於Web伺服器與Web應用程式之間的抽象層。OWIN將網頁應用程式從網頁伺服器分離出來,然後將應用程式託管於OWIN的程序而離開IIS之外。
圖片五
來源:https://www.asp.net/aspnet/overview/owin-and-katana/an-overview-of-project-katana
OWIN Welcome Page
以下透過Custom Host來實作一個OWIN的Welcome Page網頁。新增一個主控台應用程式,然後新增以下套件:
Install-Package Microsoft.Owin.Hosting -pre
Install-Package Microsoft.Owin.Host.HttpListener -pre
Install-Package Microsoft.Owin.Diagnostics -pre
Install-Package Owin.Extensions -pre
首先,建立Startup類別,進行Configuration方法設置。
using Owin;
public void Configuration(IAppBuilder app)
{
app.UseWelcomePage();
}
程式碼只有一行,UseWelcomePage擴充方法是由Microsoft.Owin.Diagnostics元件提供。接下來於主程式透過WebApp類別來啟動HttpListener。
using Microsoft.Owin.Hosting;
class Program
{
static void Main(string[] args)
{
string baseUri = "https://localhost:5000/";
using (WebApp.Start<Startup>(baseUri))
{
Console.WriteLine("OWIN啟動");
Console.ReadKey();
Console.WriteLine("OWIN結束");
}
}
}
WebApp.Start方法必須傳入Startup型別以進行相關組態與Server啟用,Server會服務在baseUri所設置的位址上。接下來即可按下「F5」或「開始」鈕,並以瀏覽器瀏覽程式碼中設置的URI:
圖七
讀者可以看到一個不依賴於IIS的應用程式現在已正常運作於Custom Host環境中。
結語
ASP.NET Web API 2增加不少不新功能,對外有Attribute routing、CORS、OData改善,開發方面提供可攜式Web API Client、IHttpActionResult介面。還有Katana專案與OWIN,讓ASP.NET Web API能運作於相容OWIN的託管環境,而不再非IIS不可。另外,未來版本中也會提供認證相關功能,以提升ASP.NET Web API在安全性的功能。
參考資料
- 1. https://channel9.msdn.com/Events/Build/2013/3-504
- 2. https://channel9.msdn.com/Shows/Web+Camps+TV/The-Katana-Project-OWIN-for-ASPNET
- 3. https://www.asp.net/vnext/overview/latest/release-notes
- 4. https://www.odata.org/documentation/odata-v2-documentation/batch-processing/
[1] https://msdn.microsoft.com/en-us/library/system.web.http.routing.urlhelper%28v=vs.108%29.aspx
[3] https://www.w3.org/TR/cors/
延伸閱讀