banner



How To Keep Session Alive In Asp Net C# Mvc

In this post I describe a problem that I've been asked about several times related to session state. The scenario goes something like this:

  • Scaffold a new ASP.Internet Core awarding
  • Set a cord in session land for a user, e.g. HttpContext.Session.SetString("theme", "Dark");
  • On the next asking, endeavour to load the value from session using HttpContext.Session.GetString("theme"); simply get back null!
  • "Gah, this stupid framework doesn't piece of work" (╯°□°)╯︵ ┻━┻

The cause of this "effect" is the interaction between the GDPR features introduced in ASP.Internet Core two.1 and the fact that session state uses cookies. In this post I describe why you see this behaviour, as well as some means to handle it.

The GDPR features were introduced in ASP.Net Cadre ii.1, and then if you lot're using ii.0 or 1.x you lot won't see these bug. Bear in mind that 1.ten are falling out of back up on June 27 2022, and two.0 is already unsupported, and then yous should consider upgrading your apps to 2.one where possible.

Session State in ASP.NET Core

As I stated in a higher place, if yous're using ASP.NET Core 2.0 or earlier, you won't come across this problem. I'll demonstrate the onetime "expected" behaviour using an ASP.Cyberspace Core ii.0, to bear witness how people experiencing the issue typically expect session state to behave. Then I'll create the equivalent app in ASP.NET Core 2.one, and prove that session state no longer seems to work.

What is session state?

Session state is a feature that harks back to ASP.Cyberspace (non-Core) in which you tin store and retrieve values server-side for a user browsing your site. Session state was often used quite extensively in ASP.NET apps, but was problematic for various reasons), primarily performance and scalability.

Session land in ASP.NET Cadre is somewhat dialled back. You should recollect of information technology more than like a per-user cache. From a technical point of view, session state in ASP.Internet Core requires two separate parts:

  • A cookie. Used to assign a unique identifier (the session ID) to a user.
  • A distributed cache. Used to store items associated with a given session ID.

Where possible, I would avoid using session state if y'all tin go away without it. There's a lot of caveats around its usage that tin can easily bite y'all if you're not aware of them. For example:

  • Sessions are per-browser, not per logged-in user
  • Session cookies (and so sessions) should exist deleted when the browser session ends, but might not be.
  • If a session doesn't accept any values in it, it will be deleted, generating a new session ID
  • The GDPR event described in this post!

That covers what session country is and how it works. In the side by side section I'll create a pocket-sized app that tracks which pages you've visited by storing a list in session state, and then displays the list on the home page.

Using session state in an ASP.Cyberspace Core 2.0 app

To demonstrate the change in behaviour related to the 2.0 to 2.1 upgrade, I'm going to start by building an ASP.NET Core 2.0 app. Every bit I patently yet accept a bazillion .NET Cadre SDKs installed on my auto, I'yard going to use the 2.0 SDK (version number two.1.202) to scaffold a ii.0 project template.

Start by creating a global.json to pin the SDK version in your app directory:

          dotnet new globaljson --sdk-version ii.1.202                  

Then scaffold a new ASP.NET Core ii.0 MVC app using dotnet new:

          dotnet new mvc --framework netcoreapp2.0                  

Session state is not configured by default, then you need to add the required services. Update ConfigureServices in Startup.cs to add the session services. By default, ASP.NET Core will utilize an in-retention session shop, which is fine for testing purposes, but will need to be updated for a product surround:

                      public            void            ConfigureServices            (            IServiceCollection            services)            {            services.            AddMvc            (            )            ;            services.            AddSession            (            )            ;            // add session            }                  

You besides need to add the session middleware to your pipeline. Just middleware added afterward the session middleware volition accept a access to session state, and then you typically add it merely before the MVC middleware in Startup.Configure:

                      public            void            Configure            (            IApplicationBuilder            app,            IHostingEnvironment            env)            {            // ...other config            app.            UseSession            (            )            ;            app.            UseMvc            (routes            =            >            {            routes.            MapRoute            (            name:            "default"            ,            template:            "{controller=Domicile}/{action=Index}/{id?}"            )            ;            }            )            ;            }                  

For this simple (toy) example I'1000 going to call up and set a string session value with each page view, using the session-cardinal "actions". As you browse between diverse pages, the session value volition expand into a semicolon-separated listing of action names. Update your HomeController to employ the RecordInSession role, as shown below:

                      public            course            HomeController            :            Controller            {            public            IActionResult            Index            (            )            {            RecordInSession            (            "Dwelling"            )            ;            render            View            (            )            ;            }            public            IActionResult            About            (            )            {            RecordInSession            (            "About"            )            ;            return            View            (            )            ;            }            individual            void            RecordInSession            (            string            action)            {            var            paths            =            HttpContext.Session.            GetString            (            "actions"            )            ?            ?            string            .Empty;            HttpContext.Session.            SetString            (            "actions"            ,            paths            +            ";"            +            action)            ;            }            }                  

Note: Session.GetString(primal) is an extension method in the Microsoft.AspNetCore.Http namespace

Finally, we'll display the current value of the "deportment" fundamental in the homepage, Index.chstml:

          @using            Microsoft.AspNetCore.Http @{            ViewData[            "Title"            ]            =            "Dwelling Page"            ;            }            <div>            @Context.Session.            GetString            (            "actions"            )            <            /div>                  

If you lot run the application and browse around a few times, you'll see the session action-list build upwardly. In the example below I visited the Dwelling page iii times, the About page twice, and the Contact page in one case:

Session working correctly

If you view the cookies associated with the folio, you will encounter the .AspNetCore.Session cookie that holds an encrypted session ID. If y'all delete this cookie, you lot'll see the "actions" value is reset, and the list is lost.

AspNetCore.Session cookie used for tracking session id

This is the behaviour most people await with session state, so no problems at that place. The difficulties arise when y'all endeavor the same thing using an ASP.NET Cadre 2.one / two.ii app.

Session country problems in ASP.Cyberspace Core 2.1/ii.2

To create the ASP.Cyberspace Core ii.ii app, I used pretty much the same behaviour, simply this time I did not pin the SDK. I take the ASP.NET Cadre 2.ii SDK installed (2.ii.102) and so the post-obit generates an ASP.Net Core 2.2 MVC app:

          dotnet new mvc                  

You withal demand to explicitly install session country, and so update Startup as before, past adding services.AddSession() to ConfigureServices and app.UseSession() to Configure.

The newer ii.ii templates have been simplified compared to previous versions, so for consistency I copied across the HomeController from the 2.0 app. I also copied across the Index.chtml, About.chtml, and Contact.cshtml view files. Finally, I updated Layout.cshtml to add links for the Well-nigh and Contact pages in the header.

These two apps, while running unlike versions of ASP.NET Cadre, are pretty much the same. Even so this time, if you click around the app, the home page always shows merely a single visit to the home folio, and doesn't record any visits to other pages:

Session not working correctly

Don't click the privacy policy banner - you'll run into why presently!

Also, if you lot cheque your cookies, you'll observe there aren't whatsoever! The .AspNetCore.Session cookie is noticeably absent-minded:

No session cookie

Everything is apparently configured correctly, and the session itself appears to be working (as the value set in the HomeController.Index action can be successfully retrieved in Alphabetize.cshtml). But information technology seems like session state isn't being saved between page reloads and navigations.

Then why does this happen in ASP.Cyberspace Core 2.1 / ii.two where it worked in ASP.NET Core two.0?

The answer is due to some new features added in ASP.Cyberspace Core 2.1. In gild to help developers accommodate to GDPR regulations that came into force in 2022, ASP.Net Core 2.1 introduced some additional extension points, also as updates to the templates. The documentation for these changes is excellent so I'll merely summarise the pertinent changes here:

  • A cookie consent dialog. By default, ASP.Internet Core won't write "non-essential" cookies to the response until a user clicks the consent dialog
  • Cookies can be marked essential or not-essential. Essential cookies are sent to the browser regardless of whether consent is provided, non-essential cookies require consent.
  • Session cookies are considered non-essential, then sessions can't exist tracked beyond navigations or page reloads until the user provides their consent.
  • Temp information is not-essential. The TempData provider stores values in cookies in ASP.Net Cadre 2.0+, so TempData will not work until the user provides their consent.

And so the problem is that we require consent to store cookies from the user. If you click "Accept" on the privacy banner, then ASP.Cyberspace Cadre is able to write the session cookie, and the expected functionality is restored:

Session state working correctly again

So if you need to apply session state in your 2.1/2.2 app, what should you practise?

Working with session state in ASP.Cyberspace Cadre ii.1+ apps

Depending on the app you're building, you have several options available to you. Which ane is best for you will depend on your use case, just be enlightened that these features were added for a reason - to assistance developers comply with GDPR.

If you're not in the Eu, and and so you lot retrieve "GDPR doesn't utilise to me", exist sure to read this not bad post from Troy Chase - it'south likely GDPR still applies to you!

The main options I see are:

  1. Accept that session state may not exist available until users provide consent.
  2. Disable features that require session state until consent is provided.
  3. Disable the cookie consent requirement.
  4. Marking the session cookie as essential.

I'll go into a fleck more than detail for each option beneath, just recall to consider that your pick might affect your conformance to GDPR!

1. Take the existing behaviour

The "easiest" option is to just to accept the existing behaviour. Session state in ASP.NET Cadre should typically merely exist used for imperceptible data, so your awarding should be able to handle the case that session state is not bachelor.

Depending on what you're using it for, that may or may not exist possible, simply it's the easiest way to work with the existing templates, and the least risky in terms of your exposure to GDPR issues.

ii. Disable optional features

The 2d option is very similar to the commencement, in that you keep the existing behaviour in place. The difference is that option 1 treats session country but as a cache, and then you lot always assume session values can come and go. Option 2 takes a slightly unlike approach, in that it segments off areas of your awarding that require session country, and makes them explicitly unavailable until consent is given.

For case, you might require session state to drive a "theme-chooser" that stores whether a user prefers a "light" or "night" theme. If consent is not given, and then yous just hide the "theme-chooser" until they have given consent.

This feels similar an improvement over option i, primarily considering of the improved user experience. If you don't account for features requiring session state, information technology could be disruptive for the user. For case, if y'all implemented option i and and then always evidence the "theme-chooser", the user could keep choosing the nighttime theme, but it would never retrieve their choice. That sounds frustrating!

There'due south merely i big caveat for this approach. Always remember that session state could go away at any moment. You should treat it like a enshroud, so you shouldn't build features bold a) it'll e'er be there (even if the user has given consent), or b) that you'll accept one session per existent user (different browsers will have different session IDs for the aforementioned logical user).

If y'all're sure that y'all don't need the cookie consent feature, y'all can easily disable the requirement in your apps. The default template even calls this out explicitly in Startup.ConfigureServices where y'all configure the CookiePolicyOptions:

                      public            void            ConfigureServices            (            IServiceCollection            services)            {            services.                          Configure              <              CookiePolicyOptions              >                        (options            =            >            {            // This lambda determines whether user consent for non-essential cookies is needed for a given asking.            options.CheckConsentNeeded            =            context            =            >            true            ;            options.MinimumSameSitePolicy            =            SameSiteMode.None;            }            )            ;            services.            AddSession            (            )            ;            // added to enable session            services.            AddMvc            (            )            .            SetCompatibilityVersion            (CompatibilityVersion.Version_2_2)            ;            }                  

The CheckConsentNeeded belongings is a predicate that is called by the framework to check whether not-essential cookies should be written to the response. If the function returns true (equally above, the default in the template), so non-essential cookies are skipped. Change this to false and session state will work without requiring cookies to be explicitly accepted.

four. Mark session cookies as essential

Disabling the cookie consent feature entirely may exist a bit heavy handed for your applications. If that's the instance, simply you desire the session state to be written even earlier the user accepts cookies, you can marker the session cookie equally essential.

Just to reiterate, session state was considered not-essential for good reason. Brand sure you can justify your decisions and potentially seek advice before making changes like this or choice 3.

There is an overload of services.AddSession() that allows you to configure SessionOptions in your Startup file. You can modify various settings such as session timeout, and you tin also customise the session cookie. To mark the cookie as essential, set IsEssential to true:

                      public            void            ConfigureServices            (            IServiceCollection            services)            {            services.                          Configure              <              CookiePolicyOptions              >                        (options            =            >            {            options.CheckConsentNeeded            =            context            =            >            true            ;            // consent required            options.MinimumSameSitePolicy            =            SameSiteMode.None;            }            )            ;            services.            AddSession            (opts            =            >            {            opts.Cookie.IsEssential            =            true            ;            // make the session cookie Essential            }            )            ;            services.            AddMvc            (            )            .            SetCompatibilityVersion            (CompatibilityVersion.Version_2_2)            ;            }                  

With this arroyo, the cookie consent banner will all the same exist shown, and non-essential cookies volition non exist written until it'south clicked. But session state will function immediately, before consent is given, as it'southward considered essential:

Privacy banner plus session state

Summary

In this mail I described an issue that I've been asked virtually several times, where developers find that their session land isn't saving correctly. This is commonly due to the GDPR features introduced in ASP.Internet Core 2.i for cookie consent and non-essential cookies.

I showed an instance of the issue in activeness, and how it differs between a 2.0 app and a two.2 app. I described how session country relies on a session cookie that is considered non-essential by default, and so is not written to the response until a user provides consent.

Finally, I described four ways to handle this behaviour: do naught and take it; disable features that rely on session state until consent is given; remove the consent requirement; and make the session cookie an essential cookie. Which option is best for you lot will depend on the app yous're building, as well as your exposure to GDPR and like legislation.

Source: https://andrewlock.net/session-state-gdpr-and-non-essential-cookies/

Posted by: charlesmistabou.blogspot.com

0 Response to "How To Keep Session Alive In Asp Net C# Mvc"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel