OWIN 中间件可以使用 http 会话吗?
Posted
技术标签:
【中文标题】OWIN 中间件可以使用 http 会话吗?【英文标题】:Can OWIN middleware use the http session? 【发布时间】:2014-06-27 05:57:57 【问题描述】:我为 ASP.NET 和 SignalR 复制了一些代码,我决定将其重写为 OWIN 中间件以删除此重复。
一旦我运行它,我注意到HttpContext.Current.Session
为空,并且我没有在我的中间件拥有的IOwinContext
上看到任何会话对象。
是否可以从 OWIN 访问 http 会话?
【问题讨论】:
【参考方案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.Session
在 OnResponseSignIn 方法中为空。代码:Provider = new CookieAuthenticationProvider() OnResponseSignIn = async context =>
【参考方案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 中执行顺序的详细信息。
【讨论】:
以上是关于OWIN 中间件可以使用 http 会话吗?的主要内容,如果未能解决你的问题,请参考以下文章