Может ли промежуточное ПО OWIN использовать сеанс http?

У меня было немного кода, который я дублировал для ASP.NET и SignalR, и я решил переписать его как промежуточное ПО OWIN, чтобы удалить это дублирование.

Как только я запустил его, я заметил, что HttpContext.Current.Session был нулевым, и я не видел ни одного объекта сеанса на IOwinContext что мое промежуточное программное обеспечение имеет.

Можно ли получить доступ к сеансу http из OWIN?

3 ответа

Решение

Да, но это довольно взломать. Он также не будет работать с SignalR, потому что SignalR ДОЛЖЕН выполняться до того, как будет получен сеанс, чтобы предотвратить длительные блокировки сеанса.

Сделайте это, чтобы включить сеанс для любого запроса:

public static class AspNetSessionExtensions
{
    public static IAppBuilder RequireAspNetSession(this IAppBuilder app)
    {
        app.Use((context, next) =>
        {
            // Depending on the handler the request gets mapped to, session might not be enabled. Force it on.
            HttpContextBase httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
            httpContext.SetSessionStateBehavior(SessionStateBehavior.Required);
            return next();
        });
        // SetSessionStateBehavior must be called before AcquireState
        app.UseStageMarker(PipelineStage.MapHandler);
        return app;
    }
}

Затем вы можете получить доступ к сеансу с помощью HttpContext.Current.Session или же

HttpContextBase httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);

Этот ответ является ремиксом из первоначального ответа, поэтому суть его должна быть приписана @Tratcher. Это достаточно отличается, хотя, чтобы разместить его отдельно, вместо того, чтобы предлагать редактирование.


Предположим, вы хотите создать небольшое приложение OWIN для базовых целей тестирования (например, в качестве заглушки / подделки для большего API при выполнении интеграционных тестов), включая слегка хакерский способ использования состояния сеанса.

Прежде всего, вам нужно это:

using Microsoft.Owin;
using Microsoft.Owin.Extensions;
using Owin;

С их помощью вы можете создать вспомогательный метод:

public static void RequireAspNetSession(IAppBuilder app)
{
    app.Use((context, next) =>
    {
        var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
        httpContext.SetSessionStateBehavior(SessionStateBehavior.Required);
        return next();
    });

    // To make sure the above `Use` is in the correct position:
    app.UseStageMarker(PipelineStage.MapHandler);
}

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

Обратите внимание, что если вы не используете UseStageMarker Вы столкнетесь с этой ошибкой:

Ошибка сервера в приложении '/'
"HttpContext.SetSessionStateBehavior" может быть вызван только до возникновения события "HttpApplication.AcquireRequestState".

В любом случае, с помощью вышеизложенного вы теперь можете использовать HttpContext в вашем OWIN-приложении следующим образом:

public void Configuration(IAppBuilder app)
{
    RequireAspNetSession(app);

    app.Run(async context =>
    {
        if (context.Request.Uri.AbsolutePath.EndsWith("write"))
        {
            HttpContext.Current.Session["data"] = DateTime.Now.ToString();
            await context.Response.WriteAsync("Wrote to session state!");
        }
        else
        {
            var data = (HttpContext.Current.Session["data"] ?? "No data in session state yet.").ToString();
            await context.Response.WriteAsync(data);
        }
    });
}

Если вы запустите IIS Express с помощью этого небольшого приложения, вы сначала получите:

Нет данных в состоянии сеанса.

Тогда, если вы идете в http://localhost:12345/write ты получишь:

Написал в сессионное состояние!

Затем, если вы вернетесь / перейдете к любому другому URL-адресу на этом хосте, вы получите:

04.11.2015, 10:28:22

Или что-то подобное.

Это старый вопрос и ответ, но ни один из ответов не был полным, поэтому я решил поделиться тем, что нашел здесь . Это отлично сработало для меня!

Сначала мне пришлось установить Owin.Extensions. Затем...

Ты почти там. Причина, по которой ваш сеанс по-прежнему равен нулю, заключается в том, что вы не указали OWIN для инициализации сеансов System.Web до выполнения вашего промежуточного программного обеспечения.

Добавив .UseStageMarker(..) после регистрации промежуточного программного обеспечения, вы сообщите OWIN, где в конвейере выполнения он должен выполнять SetSessionStateBehaviour.

      app.Use((context, next) =>
{
    var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
    httpContext.SetSessionStateBehavior(SessionStateBehavior.Required);
    return next();
});

// To make sure the above `Use` is in the correct position:
app.UseStageMarker(PipelineStage.MapHandler);

По умолчанию ПО промежуточного слоя Owin запускается при последнем событии (PipelineStage.PreHandlerExecute), что в данном случае слишком поздно для вас.

Теперь, чтобы использовать сеансы, вам нужно работать во втором промежуточном программном обеспечении, которое запускается после того, как сеанс был получен средой выполнения Asp.Net. Это промежуточное ПО должно запускаться на этапе PostAquireState, например:

      .Use((context, next) =>
 {
     // now use the session
     HttpContext.Current.Session["test"] = 1;

     return next();
})
.UseStageMarker(PipelineStage.PostAcquireState);

В Asp.Net katana docs есть отличная статья о том, как работает промежуточное ПО. См. документы перечисления PiplineStage и документы HttpApplication для получения подробной информации о порядке выполнения в Asp.net.

Другие вопросы по тегам