摘要:讓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了,其實理論上可以用最新的技術當然最好,但是有很多老專案確實有些歷史因素,導致一定還是要用一些很奇怪的做法,但偏偏又想要用更先進和方便的方式來開發,畢竟我們今天留下的程式碼,過了十年後回來看,一定也會覺得當初怎麼會做這麼麻煩或古老的方式。