web apiのRouteHandler

5328 ワード

ASP.NET MVC 4に導入されたWeb APIはRESTソフトウェア開発の利器(個人的な意見)といえるが,最近,web formにweb apiが混入した際,以前のweb formプロジェクトではsession(複雑な下位論理を含む)が使用されていたため,最小変更のためにはsessionがサポートされることを保証しなければならないという問題が発見された.Web apiのデフォルトでは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);

}

実行後、ページ出力が「セッションis null」であることがわかりました.

ソリューション


努力した結果、RouteにはIrouteHandlerタイプの属性RouteHandlerがあることが分かった.デフォルトでは、このRouteHandlerはSystemである.Web.Http.WebHost.HttpControllerRouteHandler、HttpControllerRouteHandlerのGetHttpHandlerはIHttpHandlerのオブジェクトを返し、web apiのリクエストを前処理します.IHttpHandlerについてはよく知られていないはずですが、これはaspです.Netweb formでは、よく使われるiisパイプ処理の一環です.では、IHttpHandlerがセッションをサポートするためには、タグインタフェースIRequiresSessionStateを1つだけ実現する必要があることを知っています.デフォルトのシステムです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'me 4 exrjgv 4 lecvixa 0 ab 2 z 1 g」です.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に限らずセッションをサポートします.前述したように、Web apiのリクエストを前処理したり、カスタムクラスを作成したりして、HttpControllerHandlerの次のものを再現することができます.
1、BeginProcessRequest
2、EndProcessRequest
3、ProcessRequest
具体的にどちらを書き換えるべきかは、具体的なビジネスに基づいて具体的に分析する必要があります.