【问题标题】:Can OWIN middleware use the http session?OWIN 中间件可以使用 http 会话吗?
【发布时间】:2014-06-27 05:57:57
【问题描述】:

我为 ASP.NET 和 SignalR 复制了一些代码,我决定将其重写为 OWIN 中间件以删除此重复。

一旦我运行它,我注意到HttpContext.Current.Session 为空,并且我没有在我的中间件拥有的IOwinContext 上看到任何会话对象。

是否可以从 OWIN 访问 http 会话?

【问题讨论】:

    标签: c# asp.net session owin httpsession


    【解决方案1】:

    是的,但它是一个相当黑客。它也不适用于 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);
    

    【讨论】:

    • 我的会话仍然为空。是什么原因造成的?
    • 这里还是null!!
    • @Rastko 也许这个会话黑客可以在 IIS 上与 OWIN 一起使用,但不能与自托管 OWIN 一起使用。你用的是哪个?
    • 正确,selfhost中没有会话。
    • 会话在AcquireState 阶段初始化。在此阶段之前运行的任何 Owin 中间件,例如通过使用app.UseStageMarker 将遇到会话为空,无论此修复如何。
    【解决方案2】:

    这个答案是来自the initial answer 的混音,所以它的要点应该归功于@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' 事件之前调用。

    无论如何,通过上述方法,您现在可以像这样在您的 OWIN 应用程序中使用 HttpContext:

    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你会得到:

    写入会话状态!

    然后,如果您返回/转到该主机上的任何其他网址,您将获得:

    2015 年 11 月 4 日上午 10:28:22

    或类似的东西。

    【讨论】:

    • System.Web.HttpContext.Current.SessionOnResponseSignIn 方法中为空。代码:Provider = new CookieAuthenticationProvider() { OnResponseSignIn = async context =&gt;
    【解决方案3】:

    这是一个旧的问答,但没有一个答案是完整的,所以我想我会分享我发现的 here。这对我很有用!

    首先,我必须安装 Owin.Extensions。那么……

    你快到了。您的会话仍然为空的原因是您 之前没有指示 OWIN 初始化 System.Web 会话 你的中间件正在被执行。

    通过在中间件注册后添加 .UseStageMarker(..) 你会告诉 OWIN 它应该在执行管道中的哪个位置执行 设置会话状态行为。

    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 中执行顺序的详细信息。

    【讨论】:

      猜你喜欢
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-24
      • 2010-10-11
      • 1970-01-01
      • 2015-06-04
      • 1970-01-01
      相关资源
      最近更新 更多