Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 651
user2719430 Avatar asked May 09 '14 13:05

user2719430


2 Answers

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);
like image 172
Tratcher Avatar answered Nov 17 '22 05:11

Tratcher


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.

like image 12
Jeroen Avatar answered Nov 17 '22 06:11

Jeroen