HttpContext.Current.Session is null + OWIN

2020-05-27 04:30发布

问题:

I'm entirely new to OWIN and this issue has been a major blocker for me.

Basically, at my MVC app I have the following at Startup class:

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    ClientId = OfficeSettings.ClientId,
                    Authority = OfficeSettings.Authority,

                    TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters()
                    {
                        RoleClaimType = "roles"
                    },

                    Notifications = new OpenIdConnectAuthenticationNotifications()
                    {

                    AuthorizationCodeReceived = (context) =>
                        {
                        // code hidden for readability

                            if(HttpContext.Current.Session == null)
                            {
                                // It's null. Why is that?
                            }

                            var session = HttpContext.Current.Session;
                            if (session["myMockSession"] != null)
                            {
                                // Do stuff...
                            }
                        },

                        RedirectToIdentityProvider = (context) =>
                        {
                            // code hidden for readability
                        },

                        AuthenticationFailed = (context) =>
                        {
                            // code hidden for readability
                        }
                    }
                });

I don't understand why when I'm debugging that the Session is null. HttpContext.Current Property isn't. Are there any constraints with Sessions + OWIN? Is there any workaround for this issue? How should one approach it?

Side note 1: I've tried to add this piece of code I've found in one of the SO questions and the Session was still null:

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

Side note 2: I don't seem to find it anymore, but someone suggested in one of the SO questions to add empty methods Session_Start and Session_End (as empty methods) at the Global.asax. That didn't worked neither.

I'm welcoming any advises. Thanks!

回答1:

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.