Как я могу реализовать API WEB-интерфейса для определенных контроллеров?

Я создаю несколько контроллеров 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.

Есть ли у кого-нибудь идеи?

Ответ 1

Я придумал решение, которое сработало. Я добавил второй маршрут во время регистрации маршрутов, например

        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);
        }
    }

Это позволяет любому контроллеру запрашивать информацию о сеансе или без него, поэтому решение моей проблемы.

Мое решение немного опрятно с константами конфигурации и тому подобное, но этот вышеприведенный код является примером.

Ответ 2

Имейте в виду, что работа с 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());
  }
}