溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

[水煮 ASP.NET Web API2 方法論](1-8)添加 Session 狀態(tài)

發(fā)布時(shí)間:2020-08-01 11:53:02 來源:網(wǎng)絡(luò) 閱讀:532 作者:水煮code 欄目:編程語言

問題

ASP.NET Web API 構(gòu)建 Web 應(yīng)用程序時(shí),要求使用 Session 服務(wù)器存儲(chǔ)一些用戶特定的信息

解決方案

ASP.NET Web API 不支持 Session,因?yàn)?/span> API 根本不依賴于System.Web。他想試圖擺脫偽造 Session,非 HTTP 這樣的概念。

然而,如果我們 ASP.NET 運(yùn)行時(shí)中運(yùn)行 ASP.NET Web API,還想啟用 Session。我們可以通過兩種方式來做:

  • 全局:應(yīng)用于整個(gè) API

  • 局部:應(yīng)用于指定路由

啟用全局方式,我們需要在  Global.asax 通過 SesssionStateBehavior.Required顯示的設(shè)置啟用 Session 行為。

 

protected void Application_PostAuthorizeRequest()
{
    HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}

 

 

啟用指定路由(局部方式),我們可以通過過使用路由處理器,讓路由處理器繼承自 IRequiresSessionState。然后,我們可以在指定的路由上附加處理器,這個(gè)就在請求指定路由的時(shí)候啟用了 Session

 

工作原理

默認(rèn)的 ASP.NET Web API 模板,會(huì)幫我們在 WebApiConfig 靜態(tài)類中使用 HttpConfiguration 定義默認(rèn)路由,因?yàn)?,框架附帶的擴(kuò)展方法是支持我們使用 System.Web.RouteCollection,在定義 MVC 路由的地方定義 Web API 路由。

雖然 MapHttpRoute 的多個(gè)重載方法經(jīng)常被使用,但是這些重載方法都是 void (無返回值)方法,實(shí)際上,方法還是返回了一個(gè)最新聲明路由的實(shí)例,只是方法的調(diào)用結(jié)果一般都是被拋棄掉的。在使用 Syste.Web.RouteCollection 直接定義路由的情況下,返回值是 System.Web.Route 的對象,我們可以將其賦值給 IrouteHandler。

當(dāng)運(yùn)行在 ASP.NET 的時(shí)候,ASP.NET Web API 框架使用同樣的機(jī)制來確保 Api 請求可以準(zhǔn)確到達(dá),他會(huì)賦值 HttpControllerRouteHandler 給每一個(gè) Web API 路由,HttpControllerRouteHandler GetHttpHandler 方法返回的一個(gè)HttpControllerHandler 實(shí)例,這是 ASP.NET Web API 管道的入口點(diǎn)。HttpControllerHandler WEB API 的核心)雖然很復(fù)雜,但是究其原理也就是一個(gè)傳統(tǒng)的 IHttpAsyncHandler(舊的 IHttpHandler 的一個(gè)異步的版本)。

我們可以通過實(shí)現(xiàn)IRequiresSessionState 的接口,來強(qiáng)制在 IHttpHandler 中使用 Session。ASP.NET 將會(huì)顯示的為每一個(gè)實(shí)現(xiàn)了這個(gè)接口路由啟用 Session

另外要在全局范圍內(nèi)調(diào)用 HttpContext.Current.SetSessionStateBehavior 方法和傳遞 SessionStateBehavior,需要為當(dāng)前的 HttpContext 顯示的啟用 Session。SetSessionStateBehavior方法必須在 AcquireRequestState 事件之前調(diào)用。

 

代碼演示

繼承兩個(gè)類:

  • HttpControllerHandler

  • HttpControllerRouteHandler

我們將創(chuàng)建兩個(gè)自定義類

  • SessionHttpControllerHandler:實(shí)現(xiàn)     IRequiresSessionState

  • SessionHttpControllerRouteHandler:只是代替默認(rèn)類型,來充當(dāng)返回     SessionHttpControllerHandler 的工廠

如清單 1-26 所示。

 

清單 1-26. 定制 HttpControllerHandler HttpControllerRouteHandler

 

public class SessionControllerHandler : HttpControllerHandler, IRequiresSessionState
{
    public SessionControllerHandler(RouteData routeData)
        : base(routeData)
    { }
}
public class SessionHttpControllerRouteHandler : HttpControllerRouteHandler
{
    protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new SessionControllerHandler(requestContext.RouteData);
    }
}

 

 

現(xiàn)在我們需要將我們的注意力從 WebApiConfig 類轉(zhuǎn)移到 RouteConfig 類,因?yàn)槲覀冃枰獔?zhí)行 RouteCollection。接下來,我們應(yīng)該在創(chuàng)建路由的時(shí)候,將 SessionHttpControllerRouteHandler 賦值給 RouteHandler。如清單 1-27 所示。

 

清單 1-27.  System.Web.RouteCollection 中注冊 Web API 路由

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    //Web API
    routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
    ).RouteHandler = new SessionHttpControllerRouteHandler();
    //MVC
    routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

 

 

如果想激進(jìn)一點(diǎn),還是有其他的方式來執(zhí)行這個(gè)功能的。不再需要跑到 RouteConfig 中注冊 Api 的路由,而是需要使用 WebApiConfig 中的 HttpConfiguration 做一些必要的處理,可以同樣達(dá)對所有  Web API 路由啟用 Session

當(dāng)我們通過 Web API 的配置注冊路由的時(shí)候,路由是被注冊在 RouteTable 中,同時(shí),使用一個(gè)單利 HttpControllerRouteHandler.Instance 處理器來處理路由。這樣,我們可以讓 ASP.NET 所有調(diào)用轉(zhuǎn)到Web API 路由,進(jìn)入到 Web API 的管道。這里說到的單例其實(shí)就是一個(gè) Lazy<HttpControllerRputeHandler>。我們可以在應(yīng)用程序啟動(dòng)的地方使用自己的類似 SessionHttpControllerRouteHandler 的類實(shí)例,然后繼續(xù)注冊路由到 HttpConfiguration,同時(shí),這樣可以確保每一個(gè) Web API 路由都使用了SessionHttpControllerRouteHandler ,也就是說所有的路由都可以訪問Session。這個(gè)簡單的代碼如清單 1-28 所示。


清單 1-28. 配置 Session

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var httpControllerRouteHandler = typeof(HttpControllerRouteHandler).GetField("_instance",
        BindingFlags.Static | BindingFlags.NonPublic);
        if (httpControllerRouteHandler != null)
        {
            httpControllerRouteHandler.SetValue(null,
            new Lazy<HttpControllerRouteHandler>(() => new SessionHttpControllerRouteHandler(),
            true));
        }
        config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
        );
        config.MapHttpAttributeRoutes();
    }
}

 

現(xiàn)在,我們需要證明這個(gè)起作用了,需要做一個(gè)簡單模擬擲骰子的 ApiController 例子。首先,生成一個(gè) 1 6 之間的隨機(jī)數(shù),將 Session 中上一次的值使用當(dāng)前投擲的值賦值。

 

清單 1-29. 使用 Session ApiController 簡單例子

public class DiceResult
{
    public int NewValue { get; set; }
    public int LastValue { get; set; }
}
public class DiceController : ApiController
{
    public DiceResult Get()
    {
        var newValue = new Random().Next(1, 7);
        object context;
        if (Request.Properties.TryGetValue("MS_HttpContext", out context))
        {
            var httpContext = context as HttpContextBase;
            if (httpContext != null && httpContext.Session != null)
            {
                var lastValue = httpContext.Session["LastValue"] as int?;
                httpContext.Session["LastValue"] = newValue;
                return new DiceResult
                {
                    NewValue = newValue,
                    LastValue = lastValue ?? 0
                };
            }
        }
        return new DiceResult { NewValue = newValue };
    }
}

 

值得注意的是,我們剛剛獲取的 HttpContext 是從 HttpRequestMessage 屬性字典中通過“MS_HttpContextkey”獲取的。這個(gè)比直接從 System.HttpContext.Current中獲取更具可測性。

 

博客園http://www.cnblogs.com/shuizhucode/

51 CTOhttp://shuizhucode.blog.51cto.com/


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI