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
具体的にどちらを書き換えるべきかは、具体的なビジネスに基づいて具体的に分析する必要があります.
public string Get()
{
return HttpContext.Current.Session == null ? "Session is null" : string.Format("SessionID is '{0}'", HttpContext.Current.Session.SessionID);
}
努力した結果、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
具体的にどちらを書き換えるべきかは、具体的なビジネスに基づいて具体的に分析する必要があります.
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;
}
}
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
具体的にどちらを書き換えるべきかは、具体的なビジネスに基づいて具体的に分析する必要があります.