Can OWIN middleware use the http session?

后端 未结 2 902
后悔当初
后悔当初 2020-12-09 09:26

I had a little bit of code that I was duplicating for ASP.NET and SignalR and I decided to rewrite it as OWIN middleware to remove this duplication.

Once I was runni

相关标签:
2条回答
  • 2020-12-09 10:04

    This answer is a remix from the initial answer, so the gist of it should be attributed to @Tratcher. It's different enough though to post it seperately instead of suggesting an edit.


    Supposing you want to make a small OWIN app for basic testing purposes (e.g. as a stub/fake for a bigger API when doing integration tests), including a slightly hakish way of using session state would work just fine.

    First up, you need these:

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

    With those you can create a helper method:

    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);
    }
    

    You could also create that as an extension method as the original answer did.

    Note that if you don't use the UseStageMarker you would encounter this error:

    Server Error in '/' Application.
    'HttpContext.SetSessionStateBehavior' can only be invoked before 'HttpApplication.AcquireRequestState' event is raised.

    In any case, with the above you can now use HttpContext in your OWIN app like this:

    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);
            }
        });
    }
    

    If you fire up IIS Express with this little app you'll first get:

    No data in session state yet.

    Then if you go to http://localhost:12345/write you'll get:

    Wrote to session state!

    Then if you go back / go to any other url on that host you'll get:

    11/4/2015 10:28:22 AM

    Or something similar.

    0 讨论(0)
  • 2020-12-09 10:08

    Yes, but it's quite a hack. It also won't work with SignalR because SignalR MUST run before session is acquired to prevent long session locks.

    Do this to enable session for any request:

    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;
        }
    }
    

    Then you can access the session with either HttpContext.Current.Session or

    HttpContextBase httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
    
    0 讨论(0)
提交回复
热议问题