web api中的RouteHandler


ASP.NET MVC4中引入的Web API可以說是進行REST軟件開發的利器(個人意見),但是最近在web form中混入web api時,發現一個問題:由於以前的web form項目中,使用到了session(包括那些復雜的底層邏輯),所以為了最小改動,必須保證web api能支持session。而web api默認情況下,是不支持session的。

問題重現

重現這個不支持session的問題,其實很簡單。只需要新建一個web api項目,然后修改ValuesController的Get方法為:

public string Get()
{
    return HttpContext.Current.Session == null ? "Session is null" : string.Format("SessionID is '{0}'", HttpContext.Current.Session.SessionID);
}

在運行后,發現頁面輸出為:"Session is null"。

解決方案

經過一番努力,發現Route中有一個IRouteHandler類型的屬性RouteHandler,而默認情況下,這個RouteHandler是System.Web.Http.WebHost.HttpControllerRouteHandler,而HttpControllerRouteHandler中的GetHttpHandler會返回一個IHttpHandler的對象,來對web api的請求進行預處理。對於IHttpHandler其實大家應該不陌生,這個正是asp.net web form中,經常使用到的iis管道處理的一個環節。那么為了讓IHttpHandler支持session,我們知道只需要實現一個標記接口IRequiresSessionState。而默認的System.Web.Http.WebHost.HttpControllerHandler只實現了IHttpHandler並沒有實現IRequiresSessionState。所以問題就變成了如何讓IRouteHandler的GetHttpHandler方法返回一個既實現了IHttpHandler,又實現了IRequiresSessionState對象。所以有了下面的類:

public class WebApiSessionControllerHandler : HttpControllerHandler, IRequiresSessionState 
{
    public WebApiSessionControllerHandler(RouteData routeData) : base(routeData) { }        
}

為了使用WebApiSessionControllerHandler,還需要實現一個IRouteHandler自定義類:

public class WebApiSessionRouteHandler : HttpControllerRouteHandler
{
    protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new WebApiSessionControllerHandler(requestContext.RouteData);
    }        
}

接下來,就是要讓WebApiSessionRouteHandler真正起作用的時候了,只需要在你RegisterRoutes時,把MapHttpRoute修改為:

var route = routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }                    
);
route.RouteHandler = new WebApiSessionRouteHandler(); 

現在再來看下/api/values的輸出:"SessionID is 'me4exrjgv4lecvixa0ab2z1g'",發現session不在為null。

優化方案

為了在map route操作時,能夠有一個統一的寫法,可以增加一個擴展方法:

public static class HttpRouteExtensions
{
    public static Route MapHttpRoute(this RouteCollection routes, string name, string routeTemplate, object defaults, IRouteHandler routeHandler)
    {
        object constraints = null;
        HttpMessageHandler handler = null;
        var route = routes.MapHttpRoute(name, routeTemplate, defaults, constraints, handler);
        if (routeHandler != null)
        {
            route.RouteHandler = routeHandler;
        }
        return route;
    }
}

這樣,MapHttpRoute就可以改為:

routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional },
        routeHandler: new WebApiSessionRouteHandler()
);

結論

對HttpControllerHandler使用,不僅僅局限於是web api支持session。前面已經提到我們可以對web api的請求進行預處理,也可以創建自定義類,重現HttpControllerHandler中的:

1、BeginProcessRequest

2、EndProcessRequest

3、ProcessRequest

具體應該重寫哪一個就需要根據具體的業務具體分析了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM