Подтвердить что ты не робот

Как я могу использовать стандартный объект сеанса ASP.NET в реализации службы ServiceStack

Я только начинаю работу с ServiceStack, и в качестве тестового примера я ищу, чтобы переработать существующую службу, которая построена с использованием стандартных обработчиков ASP.Net. Мне удалось заставить все работать, как я хочу, но иметь определенные аспекты, которые используют объект сеанса ASP.Net.

Я попытался добавить IRequiresSessionState в интерфейс службы:

public class SessionTestService : RestServiceBase<SessionTest>, IRequiresSessionState {
    public override object OnPost(SessionTest request) {
        // Here I want to use System.Web.HttpContext.Current.Session
    }
}

Проблема в том, что я не могу заставить ее работать, поскольку объект Session всегда равен нулю.

Я сделал много Googling и озадачил https://github.com/mythz/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Services/Secure.cs и схожу, но я не могу найти какой-либо пример кода, который делает это (что меня удивляет). Может ли кто-нибудь объяснить, почему вышеуказанное не работает, и сообщить, что мне нужно сделать, чтобы заставить его работать?

Примечание.. В конечном счете, я, вероятно, захочу заменить это на Redis или попытаюсь удалить любое требование к серверному сеансу, но я решил, что буду использовать реализацию ASP.Net на данный момент, чтобы заставить вещи работать и не дорабатывать их больше, чем это необходимо на данный момент.

4b9b3361

Ответ 1

Использование ServiceStack ISession

ServiceStack имеет новый интерфейс ISession, поддерживаемый ICacheClient, который позволяет вам использовать один и тот же ISession между MVC-контроллерами, базовыми страницами ASP.NET и веб-службами ServiceStack, которые имеют один и тот же идентификатор файла cookie, позволяющий свободно обмениваться данными между эти веб-фреймворки.

Примечание: ISession - это чистая реализация, которая полностью пропускает существующий сеанс ASP.NET с собственными компонентами ServiceStack, как описано в ServiceStack MVC PowerPack и подробно объяснены на странице Session wiki.

Чтобы легко использовать SessionStack Session (Cache и JSON Serializer), ваши контроллеры наследуют от ServiceStackController (в MVC) или PageBase (в ASP.NET)

В ServiceStack добавлена ​​новая функция проверки подлинности/проверки, о которой вы можете прочитать в вики:

Использование сеанса ASP.NET

По существу ServiceStack - это всего лишь набор облегченных IHttpHandler, работающих на ASP.NET или HttpListener хост. Если он размещен в IIS/ASP.NET(чаще всего), он работает как обычный запрос ASP.NET.

Ничто в ServiceStack не позволяет или не влияет на настроенных поставщиков кэширования и сеанса в базовом приложении ASP.NET. Если вы хотите включить его, вам необходимо настроить его как обычно в ASP.NET(то есть за пределами ServiceStack):

http://msdn.microsoft.com/en-us/library/ms178581.aspx

После настройки вы можете получить доступ к сеансу ASP.NET внутри веб-службы ServiceStack через singleton:

HttpContext.Current.Session

Или, альтернативно, через базовый ASP.NET HttpRequest с помощью:

var req = (HttpRequest)base.RequestContext.Get<IHttpRequest>().OriginalRequest;
var session = req.RequestContext.HttpContext.Session;

Хотя из-за обязательной зависимости от конфигурации XML и ухудшилась производительность по умолчанию, я предпочитаю избегать использования сеанса ASP.NET, вместо этого предпочитая использовать очиститель Клиенты кэша включены в ServiceStack.

В основном способ работы сеансов (включая ASP.NET) - это файл cookie, содержащий уникальный идентификатор, который добавляет в Response уникальную идентификацию сеанса браузера. Этот id указывает на соответствующий словарь/сборник на сервере, который представляет сеанс браузера.

Интерфейс IRequiresSession, на который вы ссылаетесь, ничего не делает по умолчанию, это просто способ сигнализировать либо об автоматическом запросе или базовом веб-сервисе, что этот запрос должен быть аутентифицирован (т.е. два места, где вы должны поместить логику проверки/аутентификации в ServiceStack).

Здесь Основная реализация Auth, которая смотрит, защищена ли веб-служба, и если да, убедитесь, что они аутентифицированы.

Здесь другая реализация аутентификации, которая вместо этого проверяет все службы, помеченные атрибутом [Аутентификация], и как включить проверку подлинности для вашей службы, добавив атрибут в DTO запроса.

Новая модель аутентификации в ServiceStack

Вышеупомянутая реализация отличается от модели поставщика с несколькими авторизациями, включенной в следующую версию ServiceStack. Здесь ссылочный пример, показывающий, как регистрировать и настраивать новую модель Auth в вашем приложении.

Стратегии аутентификации

Новая модель Auth полностью исключает удобство, так как вы просто не можете ее использовать и сами реализуете подобное поведение, используя Фильтры запроса или в базовых классах (путем переопределения OnBeforeExecute). Фактически новые службы Auth фактически не встроены в ServiceStack per-se. Вся реализация находится в дополнительном проекте ServiceStack.ServiceInterfaces и реализована с использованием пользовательских фильтров запросов.

Вот несколько разных стратегий аутентификации, которые я использовал за эти годы:

  • Отметьте службы, для которых требуется аутентификация с помощью [Атрибут], Вероятно, самый идиоматический способ С#, идеальный, когда session-id передается через Cookie.

  • Особенно за пределами веб-контекста, иногда использование более явного интерфейса IRequiresAuthentication лучше, поскольку он обеспечивает строго типизированный доступ к User и SessionId, необходимый для аутентификации.

  • У вас может быть только 1-лайнер для аутентификации для каждой службы, которая ему нужна - на основе adhoc. Подход, когда у вас очень мало служб, требующих аутентификации.

Ответ 2

Это отличный и исчерпывающий ответ от @mythz. Однако при попытке доступа к сеансу ASP.NET с помощью HttpContext.Current.Session в веб-службе ServiceStack он всегда возвращает null для меня. Это потому, что ни один из HttpHandlers в ServiceStack не украшен интерфейсом IRequiresSessionState, поэтому .NET Framework не предоставляет нам объект сеанса.

Чтобы обойти это, я реализовал два новых класса, оба из которых используют шаблон декоратора, чтобы предоставить нам то, что нам нужно.

Во-первых, новый IHttpHandler, который требует состояния сеанса. Он обертывает IHttpHandler, предоставляемый ServiceStack, и передает ему вызовы...

public class SessionHandlerDecorator : IHttpHandler, IRequiresSessionState {
    private IHttpHandler Handler { get; set; }

    internal SessionHandlerDecorator(IHttpHandler handler) {
        this.Handler = handler;
    }

    public bool IsReusable {
        get { return Handler.IsReusable; }
    }

    public void ProcessRequest(HttpContext context) {
        Handler.ProcessRequest(context);
    }
}

Далее, новый IHttpHandlerFactory, который делегирует ответственность за создание IHttpHandler в ServiceStack, перед переносом возвращаемого обработчика в наш новый SessionHandlerDecorator...

public class SessionHttpHandlerFactory : IHttpHandlerFactory {
    private readonly static ServiceStackHttpHandlerFactory factory = new ServiceStackHttpHandlerFactory();

    public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated) {
        var handler = factory.GetHandler(context, requestType, url, pathTranslated);
        return handler == null ? null : new SessionHandlerDecorator(handler);
    }

    public void ReleaseHandler(IHttpHandler handler) {
        factory.ReleaseHandler(handler);
    }

}

Затем просто нужно изменить атрибуты type в обработчиках в Web.config на SessionHttpHandlerFactory вместо ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack, а ваши веб-службы должны теперь иметь доступ к сеансу ASP.NET.

Несмотря на вышеизложенное, я полностью поддерживаю новую реализацию ISession, предоставляемую ServiceStack. Однако в некоторых случаях на зрелом продукте просто кажется слишком большой задачей заменить все применения сеанса ASP.NET новой реализацией, следовательно, это обходное решение!

Ответ 3

Спасибо @Richard за ваш ответ выше. Я запускаю новую версию стека службы, и они удалили ServiceStackHttpFactory с помощью HttpFactory. Вместо того, чтобы

private readonly static ServiceStackHttpHandlerFactory factory = new ServiceStackHttpHandlerFactory();

Вам нужно

private static readonly HttpHandlerFactory Factory = new HttpHandlerFactory();

Здесь обновлен код этой службы

using ServiceStack;
using System.Web;
using System.Web.SessionState;

namespace MaryKay.eCommerce.Mappers.AMR.Host
{
public class SessionHttpHandlerFactory : IHttpHandlerFactory
{
    private static readonly HttpHandlerFactory Factory = new HttpHandlerFactory();
    public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
    {
        var handler = Factory.GetHandler(context, requestType, url, pathTranslated);
        return handler == null ? null : new SessionHandlerDecorator(handler);
    }

    public void ReleaseHandler(IHttpHandler handler)
    {
        Factory.ReleaseHandler(handler);
    }
}

public class SessionHandlerDecorator : IHttpHandler, IRequiresSessionState
{
    private IHttpHandler Handler { get; set; }

    internal SessionHandlerDecorator(IHttpHandler handler)
    {
        Handler = handler;
    }

    public bool IsReusable
    {
        get { return Handler.IsReusable; }
    }

    public void ProcessRequest(HttpContext context)
    {
        Handler.ProcessRequest(context);
    }
}
}

Ответ 4

Как и в ServiceStack 4.5+, HttpHandler также может поддерживать Async. Например:

namespace FboOne.Services.Host
{
  public class SessionHttpHandlerFactory : IHttpHandlerFactory
  {
    private static readonly HttpHandlerFactory Factory = new HttpHandlerFactory();

    public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
    {
      var handler = Factory.GetHandler(context, requestType, url, pathTranslated);
      return handler == null ? null : new SessionHandlerDecorator((IHttpAsyncHandler)handler);
    }

    public void ReleaseHandler(IHttpHandler handler)
    {
      Factory.ReleaseHandler(handler);
    }
  }

  public class SessionHandlerDecorator : IHttpAsyncHandler, IRequiresSessionState
  {
    private IHttpAsyncHandler Handler { get; set; }

    internal SessionHandlerDecorator(IHttpAsyncHandler handler)
    {
      Handler = handler;
    }

    public bool IsReusable
    {
      get { return Handler.IsReusable; }
    }

    public void ProcessRequest(HttpContext context)
    {
      Handler.ProcessRequest(context);
    }

    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
    {
      return Handler.BeginProcessRequest(context, cb, extraData);
    }

    public void EndProcessRequest(IAsyncResult result)
    {
      Handler.EndProcessRequest(result);
    }
  }
}