如何在特定控制器上实现会话感知WEB API?

时间:2015-04-02 08:45:11

标签: c# asp.net asp.net-mvc asp.net-web-api

我正在创建一些需要会话感知的WEB API 2控制器。我以前通过添加

完成了这项工作
/// <summary>
/// Application_s the post authorize request.
/// </summary>
protected void Application_PostAuthorizeRequest()
{
     HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}

然而,我们在解决方案中为站点的其他关键部分提供API控制器,这些部分已经过高度优化,并且返回的响应时间约为500毫秒,如果启用它,则一直持续2秒。这些控制器不需要会话感知。

我们只需要某些控制器可以访问会话,我已经阅读了这篇文章http://www.codeproject.com/Tips/513522/Providing-session-state-in-ASP-NET-WebAPI,并且正在考虑是否可以添加具有会话感知功能的其他路由,但是没有映射路由时的RouteHandler 属性。

有没有人有任何想法?

2 个答案:

答案 0 :(得分:3)

我提出了一个有效的解决方案。我在路线注册期间添加了第二条路线,例如

        config.Routes.MapHttpRoute(
            name: "DefaultSessionApi",
            routeTemplate: "sessionapi/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional });

然后在global.asax.cs中我有

    /// <summary>
    /// Application_s the post authorize request.
    /// </summary>
    protected void Application_PostAuthorizeRequest()
    {
        if (HttpContext.Current.Request.FilePath.StartsWith("/sessionapi"))
        {
            HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
        }
    }

这允许任何控制器具有会话感知请求,或者不允许客户端解决我的问题。

我的解决方案有点整洁,配置常量等,但上面的代码就是例子。

答案 1 :(得分:3)

请记住,使用SessionStateBehavior.Required会产生相当大的影响,并且只有部分路由实际上需要对会话的写访问权。最糟糕的是,每个用户只能处理一个请求,因为会话必须被锁定。

话虽如此,有一种方法可以根据路线不同地处理会话。

您可以使用IHttpRoute.DataTokens向路线添加自定义字段。 我创建了一个小扩展类来为每个路由单独设置SessionStateBehavior:

public static class SessionHelper
{
  private static SessionStateBehavior GetSessionStateBehavior(IDictionary<string, object> dataTokens)
  {
    return dataTokens.ContainsKey("SessionStateBehavior") ? (SessionStateBehavior)dataTokens["SessionStateBehavior"] : SessionStateBehavior.Default;
  }

  public static SessionStateBehavior GetSessionStateBehavior(this IHttpRoute route)
  {
    return GetSessionStateBehavior(route.DataTokens);
  }

  public static SessionStateBehavior GetSessionStateBehavior(this RouteData routeData)
  {
    return GetSessionStateBehavior(routeData.DataTokens);
  }

  public static void SetSessionStateBehavior(this IHttpRoute route, SessionStateBehavior behavior)
  {
    route.DataTokens["SessionStateBehavior"] = behavior;
  }

  public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, SessionStateBehavior behavior)
  {
    return MapHttpRoute(routes, name, routeTemplate, defaults, null, behavior);
  }

  public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, SessionStateBehavior behavior)
  {
    var route = routes.CreateRoute(routeTemplate, defaults, constraints);
    SetSessionStateBehavior(route, behavior);
    routes.Add(name, route);

    return route;
  }
}

设置路线时,您可以使用扩展程序定义特定的会话状态行为:

config.Routes.MapHttpRoute(
    "DefaultSessionApi",
    "api/{controller}/{id}",
    new { id = RouteParameter.Optional },
    SessionStateBehavior.ReadOnly);

config.Routes.MapHttpRoute(
    "WriteStuffToSession",
    "api/writestufftosession",
    null,
    SessionStateBehavior.Required);

然后,在PostAuthorizeRequest事件中,您可以解析路由并相应地设置SessionStateBehavior:

protected void Application_PostAuthorizeRequest()
{
  var context = new HttpContextWrapper(HttpContext.Current);
  var path = context.Request.AppRelativeCurrentExecutionFilePath;
  if (path == null || !path.StartsWith("~/api"))
  {
    return;
  }

  var routeData = RouteTable.Routes.GetRouteData(context);
  if (routeData != null)
  {
    context.SetSessionStateBehavior(routeData.GetSessionStateBehavior());
  }
}