25

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?

mai
  • 464
  • 4
  • 23
user2719430
  • 544
  • 1
  • 4
  • 15

3 Answers3

35

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);
kenchilada
  • 7,469
  • 5
  • 25
  • 34
Tratcher
  • 5,929
  • 34
  • 44
  • 4
    My session is still null. What can cause that ? – Rastko Sep 03 '17 at 12:47
  • Same here, it's still `null` !! – Ananda G Feb 06 '18 at 08:37
  • 5
    @Rastko Perhaps this session hack works with OWIN on IIS but not self-hosted OWIN. Which were you using? – BillVo Jun 28 '18 at 13:36
  • Correct, there is no session in selfhost. – Tratcher Jun 28 '18 at 17:22
  • 1
    The session gets initialized in `AcquireState` stage. Any Owin middleware which runs before this stage e.g. through the use of `app.UseStageMarker` will encounter the session as null, regardless of this fix. – Jeroen Sep 04 '20 at 22:17
  • Maybe this was the best answer in 2015, but in 2022 this approach did not perform well under high load. We had 2-4x increase in PT page response time after this change. In 2022, there is a PostAcquireState stage marker that apparently tells OWIN to wait for session state to be acquired before executing that middleware. After removing the code in this answer, and using PostAcquireState stage marker for middlewares that required session, everything still worked and performance wasn't impacted (*still testing). – Mark Good Sep 20 '22 at 23:59
12

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.

Community
  • 1
  • 1
Jeroen
  • 60,696
  • 40
  • 206
  • 339
  • 4
    `System.Web.HttpContext.Current.Session` is null in ***OnResponseSignIn*** method. Code: `Provider = new CookieAuthenticationProvider() { OnResponseSignIn = async context =>` – Kiquenet May 20 '16 at 10:08
1

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.

Mark Good
  • 4,271
  • 2
  • 31
  • 43