(2017/03/21更新)讓web api可以使用SESSION

摘要:讓web api可以使用SESSION

不知道有沒有人有這個需求,害我卡了幾小時,原來是web api是無狀態的,不過google一下還是有神人給了解決方法。

上次的說明有點錯誤,所以我在此在更正一下,目前專案是用web api2,然後用angularjs來做VIEW的部份

然後專案有切層,經我目前測試,WEB API有成功儲存SESSION,然後在類別庫裡面呼叫使用

所以在此貼出解決方法供各位參考。

因為最近要把前端專案導成spa方式的,但是因為現有的網站是十年以上的web form網站,在經過討論之後希望使用web api,但又希望保留session的機制,然後同時token要並行,在三年前我有嘗試過用web api來儲存session,也放在azure上測試過,不過三年後的今天嘗試用此作法,web api已經更新到不能這樣子做了,所以重新記錄一下此做法,而且也測試得更完整,以確認這種方式是可行的。

先在api專案加個Infrastructure的目錄,在此我又多建立了一個Sesssion的目錄,接著建立SessionableControllerHandler.cs和SessionStateRouteHandler.cs

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

 

接著需要在WebApiConfig.cs加入下面的程式碼

 //下面是新加的
            var httpControllerRouteHandler = typeof(HttpControllerRouteHandler).GetField("_instance",
        System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

            if (httpControllerRouteHandler != null)
            {
                httpControllerRouteHandler.SetValue(null,
                    new Lazy<HttpControllerRouteHandler>(() => new SessionStateRouteHandler(), true));
            }
            
            // 下面是原本的
            config.MapHttpAttributeRoutes();

接著我就先用本機測試,測試方式為開兩個瀏覽器,一個是chrome一個是firefox,然後建一個寫入session和一個是取得session的值,以下是示例圖的部份

chrome的部份

firefox的部份

測試完成模擬不同瀏覽器不同使用者確實能在web api執行session,接著則是把此應用佈署到線上iis測試,也確實可行

更簡單的實作方式(感謝john wu告知)

只要在Global.asax裡面加入下面的程式碼,就能在web api使用session了,之前的實作就都不用了,只要在此生命週期開啟session就行了

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

結論

但請注意筆者測試的都是單機ap的,如果有多台機器的需求,用其他方式來保持狀態應該會是更好的方式,時常有看到人說即然都用web api就不要用session了,其實理論上可以用最新的技術當然最好,但是有很多老專案確實有些歷史因素,導致一定還是要用一些很奇怪的做法,但偏偏又想要用更先進和方便的方式來開發,畢竟我們今天留下的程式碼,過了十年後回來看,一定也會覺得當初怎麼會做這麼麻煩或古老的方式。