進擊的 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 StoreWindows 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。如果全部設置,預設由內而外執行,即:

  1. Action
  2. Controller
  3. 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. 1.          https://channel9.msdn.com/Events/Build/2013/3-504
  2. 2.          https://channel9.msdn.com/Shows/Web+Camps+TV/The-Katana-Project-OWIN-for-ASPNET
  3. 3.          https://www.asp.net/vnext/overview/latest/release-notes
  4. 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

[2] https://brockallen.com/

[3] https://www.w3.org/TR/cors/

[4] https://owin.org

 

 

延伸閱讀