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

StackOverflow https://stackoverflow.com/questions/8339584

  •  26-10-2019
  •  | 
  •  

Вопрос

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

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

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

Это было полезно?

Решение

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

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

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

Чтобы легко использовать сеанс ServiceStack (кэш и сериализатор JSON), ваши контроллеры наследуются от СервисСтекконтроллер (в MVC) или База страниц (в ASP.NET)

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

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

По сути СервисСтек это просто набор легких IHttpHandler's работающий на хосте 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 через синглтон:

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, содержащий уникальный идентификатор добавляется в ответ, однозначно идентифицирующий сеанс браузера.Этот идентификатор указывает на соответствующий словарь/коллекцию на сервере, который представляет сеанс браузера.

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

Вот Базовая реализация аутентификации он проверяет, является ли веб-служба безопасной, и если да, то убедитесь, что они прошли аутентификацию.

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

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

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

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

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

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

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

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

  • Вы можете просто использовать однострочную аутентификацию для каждой службы, которая в ней нуждается — на разовой основе.Подходящий подход, когда у вас очень мало сервисов, требующих аутентификации.

Другие советы

Это отличный и всесторонний ответ @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 на подборе, прежде чем завершить возвращенного обработчика в нашем новом 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 to SessionHttpHandlerFactory вместо ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack, и ваши веб -сервисы теперь должны иметь сессию asp.net для них.

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

Спасибо @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);
    }
}
}

По состоянию на 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);
    }
  }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top