天天看點

如何讓ASP.NET Web API的Action方法在希望的Culture下執行

Culture的方式來解決Localization的問題。如果你對ASP.NET Web

API的執行機制有足夠了解的話,你會發現實際上有很多種解決方案。不過這些解決方案都不夠完美,原因很簡單:ASP.NET Web

API的整個架構均采用基于Task的并行程式設計模式,是以每個可擴充元件均可以在不同的線程中執行,這樣會導緻我們沒有辦法100%控制目标方法真正執行的線程的UI

Culture。不過在預設情況下,大部分元件是按照同步的方式執行的,是以我們之需要在目标Action方法執行之前設定目前線程的UI

Culture即可。

目錄 一、兩個輔助的擴充方法 二、第1種方案:自定義ActionFilter 三、第2種方案:自定義HttpActionDescriptor 四、第3種方案:自定義HttpActionInvoker 五、第4種方案:為HttpController建立一個基類

我們針對HttpRequestMessage定義了如下兩個擴充方法。SetCurrentUICulture從請求的Accpet-Language報頭提取用戶端接受的語言并據此設定目前線程的UI

Culture。在這之前,它會将目前線程的UI

Culture儲存到HttpRequestMessage對象中。ResetCurrentUICulture方法将這個CultureInfo對象從HttpRequestMessage其中提取出來,将目前線程的UI

Cuilture回複到之前的狀态。

我想這應該是大家最容易想到的解決方案,因為ActionFilter可以注冊一些回調操作在目标Action方法執行前後被自動調用。為此我們定義了如下一個繼承自ActionFilterAttribute的UseAcceptCultureAttribute類型。我們分别在重寫的OnActionExecuting和OnActionExecuted方法中利用上面定義的兩個擴充方法對目前線程的UI

Culture進行設定和恢複。

為了驗證這個ActionFilterAttribute特性,我們定義了如下一個繼承自ApiController的HelloController。唯一的Action方法傳回的字元串是從資源檔案中提取的(類型Resources為資源檔案自動生成的類型),而ActionFilterAttribute就應用在這個Get方法上。

          [UseAcceptCulture]

我們定義了兩個資源檔案,一個為語言文化中性的Resources.resx,另一個則是針對中文的Resources.zh.resx。唯一的資源項HelloWorld分别在所在的檔案中以英文和中文進行定義,而上面定義的Get方法傳回的正式它們的值。

如何讓ASP.NET Web API的Action方法在希望的Culture下執行

在啟動之後,我們利用Fiddler來調用定義在HelloController中的Action方法Get,并手工設定Accept-Language報頭的值。如下圖所示,當請求的Accept-Language報頭被分别設定為“en-US;q=1.0,

zh-CN;q=0.8”和“en-US;q=0.8,

zh-CN;q=1.0”時(即給en-US和zh-CN配置設定不同的Quality),傳回的内容分别是英文和中文。

如何讓ASP.NET Web API的Action方法在希望的Culture下執行

HttpActionDescriptor用于描述定義在HttpController中的Action,預設的HttpActionDescriptor類型為ReflectedHttpActionDescriptor。Action方法的執行最終實作在HttpActionDescriptor的ExecuteAsync方法中,我們可以通過自定義的HttpActionDescriptor的方式在目标Action方法執行前後對目前線程的UI

Culture進行設定和恢複。為此,我們定義了如下一個ExtendedReflectedHttpActionDescriptor類型。在重寫的ExecuteAsync方法中,我們調用基類的同名方法執行目标Action方法,并在這前後分别調用目前HttpRequestMessage的兩個擴充方法設定和恢複目前線程的UI

Culture。

ASP.NET Web

API利用一個名為HttpActionSelector的對象來選擇與目前請求比對的HttpActionDescriptor,要讓我們自定義的ExtendedReflectedHttpActionDescriptor被使用,我們得對應的HttpActionSelector。ASP.NET

Web

API預設使用的HttpActionSelector類型為ApiControllerActionSelector,我們自定義的ExtentedApiControllerActionSelector就繼承于它。如下面的代碼片斷所示,在重寫的SelectAction方法中,我們調用基類的同名方法得到一個ReflectedHttpActionDescriptor

對象,并根據它建立一個ExtendedReflectedHttpActionDescriptor 對象并傳回。

自定義的ExtentedApiControllerActionSelector可以在Global.asax中按照如下的方式進行注冊。

目标Action的執行是通過一個名為HttpActionInvoker驅動執行的(它調用HttpActionDescriptor的ExecuteAsync方法),預設的HttpActionInvoker類型為ApiControllerActionInvoker。我們可以繼承它,并在執行目标Action方法前後設定和恢複目前線程的UI

Culture。為此我定義了如下一個ExtendedApiControllerActionInvoker,在重寫的InvokeActionAsync方法中,我們調用基類的同名方法執行目标Action方法,并在這前後分别調用目前HttpRequestMessage的兩個擴充方法設定和恢複目前線程的UI

自定義的ExtendedApiControllerActionInvoker可以在Global.asax中按照如下的方式進行注冊。

HttpActionInvoker的最終又是在執行HttpController時被調用的,是以我們可以在執行HttpController上作文章。是以我們定義了如下一個繼承自ApiController的ExtendedApiController

類型。在重寫的ExecuteAsync方法中,我們調用基類同名方法前後對目前線程的UI Culture進行了設定和恢複。

那麼我們的HelloController隻需要繼承自ExtendedApiController 即可。

作者:蔣金楠

微信公衆賬号:大内老A

如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識别二維碼)關注個人公衆号(原來公衆帳号蔣金楠的自媒體将會停用)。

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

<a href="http://www.cnblogs.com/artech/p/asp-net-web-api-localization.html" target="_blank">原文連結</a>

繼續閱讀