Can OWIN middleware use the http session?

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 running it I noticed that HttpContext.Current.Session was null, and I didn’t see any session object on the IOwinContext that my middleware has.

Is it possible to access the http session from OWIN?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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

Method 2

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.

Method 3

This is an old Q&A, but none of the answers were complete so I thought I would share what I found here. This worked great for me!

First, I had to install Owin.Extensions. Then…

You’re almost there. The reason your session is still null is that you
have not instructed OWIN to initialize System.Web Sessions prior to
your middleware is beeing executed.

By adding .UseStageMarker(..) after your middleware registration
you’ll tell OWIN where in the execution pipline it should perform
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);

By default, Owin Middleware run at the last event
(PipelineStage.PreHandlerExecute) which is too late for you in this
case.

Now, to use sessions, you need to work in a second middleware, that
runs after the session has been Aquired by the Asp.Net runtime. This
middleware must be run in the PostAquireState phase, like so:

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

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

Asp.Net katana docs has an excellent article on how the middleware
works. See the PiplineStage enum docs and the HttpApplication docs for
details on the execution order in Asp.net.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x