[水煮 ASP.NET Web API2 方法论](1-8)添加 Session 状态
2016-11-10 08:04
357 查看
问题ASP.NET Web API 构建 Web 应用程序时,要求使用 Session 在服务器存储一些用户特定的信息解决方案ASP.NET Web API 不支持 Session,因为 API 根本不依赖于System.Web。他想试图摆脱伪造 Session,非 HTTP 这样的概念。然而,如果我们 在 ASP.NET 运行时中运行 ASP.NET Web API,还想启用 Session。我们可以通过两种方式来做:全局:应用于整个 API
局部:应用于指定路由
启用全局方式,我们需要在 Global.asax 中 通过 SesssionStateBehavior.Required显示的设置启用 Session 行为。
Web API 框架使用同样的机制来确保 Api 请求可以准确到达,他会赋值 HttpControllerRouteHandler 给每一个 Web API 路由,HttpControllerRouteHandler 是 GetHttpHandler 方法返回的一个HttpControllerHandler 实例,这是 ASP.NET Web API 管道的入口点。HttpControllerHandler (WEB API 的核心)虽然很复杂,但是究其原理也就是一个传统的 IHttpAsyncHandler(旧的 IHttpHandler 的一个异步的版本)。我们可以通过实现IRequiresSessionState 的接口,来强制在 IHttpHandler 中使用 Session。ASP.NET 将会显示的为每一个实现了这个接口路由启用 Session。另外要在全局范围内调用 HttpContext.Current.SetSessionStateBehavior 方法和传递 SessionStateBehavior,需要为当前的 HttpContext 显示的启用 Session。SetSessionStateBehavior方法必须在 AcquireRequestState 事件之前调用。 代码演示继承两个类:HttpControllerHandler
HttpControllerRouteHandler
我们将创建两个自定义类SessionHttpControllerHandler:实现
IRequiresSessionState
SessionHttpControllerRouteHandler:只是代替默认类型,来充当返回
SessionHttpControllerHandler 的工厂
如清单 1-26 所示。 清单 1-26. 定制 HttpControllerHandler和 HttpControllerRouteHandler
清单 1-28. 配置 Session
局部:应用于指定路由
启用全局方式,我们需要在 Global.asax 中 通过 SesssionStateBehavior.Required显示的设置启用 Session 行为。
protected void Application_PostAuthorizeRequest() { HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required); }启用指定路由(局部方式),我们可以通过过使用路由处理器,让路由处理器继承自 IRequiresSessionState。然后,我们可以在指定的路由上附加处理器,这个就在请求指定路由的时候启用了 Session。 工作原理默认的 ASP.NET Web API 模板,会帮我们在 WebApiConfig 静态类中使用 HttpConfiguration 定义默认路由,因为,框架附带的扩展方法是支持我们使用 System.Web.RouteCollection,在定义 MVC 路由的地方定义 Web API 路由。虽然 MapHttpRoute 的多个重载方法经常被使用,但是这些重载方法都是 void (无返回值)方法,实际上,方法还是返回了一个最新声明路由的实例,只是方法的调用结果一般都是被抛弃掉的。在使用 Syste.Web.RouteCollection 直接定义路由的情况下,返回值是 System.Web.Route 的对象,我们可以将其赋值给 IrouteHandler。当运行在 ASP.NET 的时候,ASP.NET
Web API 框架使用同样的机制来确保 Api 请求可以准确到达,他会赋值 HttpControllerRouteHandler 给每一个 Web API 路由,HttpControllerRouteHandler 是 GetHttpHandler 方法返回的一个HttpControllerHandler 实例,这是 ASP.NET Web API 管道的入口点。HttpControllerHandler (WEB API 的核心)虽然很复杂,但是究其原理也就是一个传统的 IHttpAsyncHandler(旧的 IHttpHandler 的一个异步的版本)。我们可以通过实现IRequiresSessionState 的接口,来强制在 IHttpHandler 中使用 Session。ASP.NET 将会显示的为每一个实现了这个接口路由启用 Session。另外要在全局范围内调用 HttpContext.Current.SetSessionStateBehavior 方法和传递 SessionStateBehavior,需要为当前的 HttpContext 显示的启用 Session。SetSessionStateBehavior方法必须在 AcquireRequestState 事件之前调用。 代码演示继承两个类:HttpControllerHandler
HttpControllerRouteHandler
我们将创建两个自定义类SessionHttpControllerHandler:实现
IRequiresSessionState
SessionHttpControllerRouteHandler:只是代替默认类型,来充当返回
SessionHttpControllerHandler 的工厂
如清单 1-26 所示。 清单 1-26. 定制 HttpControllerHandler和 HttpControllerRouteHandler
public class SessionControllerHandler : HttpControllerHandler, IRequiresSessionState { public SessionControllerHandler(RouteData routeData) : base(routeData) { } } public class SessionHttpControllerRouteHandler : HttpControllerRouteHandler { protected override IHttpHandler GetHttpHandler(RequestContext requestContext) { return new SessionControllerHandler(requestContext.RouteData); } }现在我们需要将我们的注意力从 WebApiConfig 类转移到 RouteConfig 类,因为我们需要执行 RouteCollection。接下来,我们应该在创建路由的时候,将 SessionHttpControllerRouteHandler 赋值给 RouteHandler。如清单 1-27 所示。 清单 1-27. 在System.Web.RouteCollection 中注册 Web API 路由
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); //Web API routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ).RouteHandler = new SessionHttpControllerRouteHandler(); //MVC routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); }如果想激进一点,还是有其他的方式来执行这个功能的。不再需要跑到 RouteConfig 中注册 Api 的路由,而是需要使用 WebApiConfig 中的 HttpConfiguration 做一些必要的处理,可以同样达对所有 Web API 路由启用 Session。当我们通过 Web API 的配置注册路由的时候,路由是被注册在 RouteTable 中,同时,使用一个单利 HttpControllerRouteHandler.Instance 处理器来处理路由。这样,我们可以让 ASP.NET 所有调用转到Web API 路由,进入到 Web API 的管道。这里说到的单例其实就是一个 Lazy<HttpControllerRputeHandler>。我们可以在应用程序启动的地方使用自己的类似 SessionHttpControllerRouteHandler 的类实例,然后继续注册路由到 HttpConfiguration,同时,这样可以确保每一个 Web API 路由都使用了SessionHttpControllerRouteHandler ,也就是说所有的路由都可以访问Session。这个简单的代码如清单 1-28 所示。
清单 1-28. 配置 Session
public static class WebApiConfig { public static void Register(HttpConfiguration config) { var httpControllerRouteHandler = typeof(HttpControllerRouteHandler).GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic); if (httpControllerRouteHandler != null) { httpControllerRouteHandler.SetValue(null, new Lazy<HttpControllerRouteHandler>(() => new SessionHttpControllerRouteHandler(), true)); } config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); config.MapHttpAttributeRoutes(); } }现在,我们需要证明这个起作用了,需要做一个简单模拟掷骰子的 ApiController 例子。首先,生成一个 1 到 6 之间的随机数,将 Session 中上一次的值使用当前投掷的值赋值。 清单 1-29. 使用 Session 的 ApiController 简单例子
public class DiceResult { public int NewValue { get; set; } public int LastValue { get; set; } } public class DiceController : ApiController { public DiceResult Get() { var newValue = new Random().Next(1, 7); object context; if (Request.Properties.TryGetValue("MS_HttpContext", out context)) { var httpContext = context as HttpContextBase; if (httpContext != null && httpContext.Session != null) { var lastValue = httpContext.Session["LastValue"] as int?; httpContext.Session["LastValue"] = newValue; return new DiceResult { NewValue = newValue, LastValue = lastValue ?? 0 }; } } return new DiceResult { NewValue = newValue }; } }值得注意的是,我们刚刚获取的 HttpContext 是从 HttpRequestMessage 属性字典中通过“MS_HttpContextkey”获取的。这个比直接从 System.HttpContext.Current中获取更具可测性。 博客园:http://www.cnblogs.com/shuizhucode/51 CTO:http://shuizhucode.blog.51cto.com/
相关文章推荐
- [水煮 ASP.NET Web API2 方法论](1-8)添加 Session 状态
- [水煮 ASP.NET Web API2 方法论](1-2)在 WebForm 应用程序中添加 ASP.NET Web API
- [水煮 ASP.NET Web API2 方法论](1-1)在MVC 应用程序中添加 ASP.NET Web API
- [水煮 ASP.NET Web API2 方法论](1-2)在 WebForm 应用程序中添加 ASP.NET Web API
- [水煮 ASP.NET Web API2 方法论](1-1)在MVC 应用程序中添加 ASP.NET Web API
- [水煮 ASP.NET Web API2 方法论](1-4)从 MVC Controller 链接到 API Controller 以及反向链接
- [水煮 ASP.NET Web API2 方法论](1-3)如何接收 HTML 表单请求
- [水煮 ASP.NET Web API2 方法论](3-8)怎样给指定路由配置处理器
- [水煮 ASP.NET Web API2 方法论](1-6)Model Validation
- [水煮 ASP.NET Web API2 方法论](3-4)设置路由可选项
- [水煮 ASP.NET Web API2 方法论](12-1)创建 OData
- [水煮 ASP.NET Web API2 方法论](12-1)创建 OData
- [水煮 ASP.NET Web API2 方法论](3-5)路由约束
- [水煮 ASP.NET Web API2 方法论](12-3)OData 查询
- [水煮 ASP.NET Web API2 方法论](1-4)从 MVC Controller 链接到 API Controller 以及反向链接
- [水煮 ASP.NET Web API2 方法论](3-1)集中式路由
- [水煮 ASP.NET Web API2 方法论](3-9)空气路由的设置
- [水煮 ASP.NET Web API2 方法论](1-6)Model Validation
- [水煮 ASP.NET Web API2 方法论](1-7)CSRF-Cross-Site Request Forgery
- [水煮 ASP.NET Web API2 方法论](3-3)路由默认值