Practical .NET

Working with Session in ASP.NET MVC Core (or: Why You Can't Migrate)

[Editor's note: Peter rewrote this article after a reader pointed out he over-engineered his original solution. ("What can I say: The code worked -- I just didn't need nearly as much code as I thought I did to get there.") Which explains the reader comments at the end.]

The first thing to know about working with the Session object in ASP.NET MVC Core is that it's different (and it doesn't matter if you've worked in ASP, ASP.NET Web Forms, or ASP.NET MVC: In ASP.NET MVC Core, Session is different). Different enough that it makes Microsoft's point that you can't reasonably expect to migrate your ASP.NET MVC application to ASP.NET MVC Core. I'm not going to argue with that ... but if you do need to migrate an application, I have some ideas on how to ease the pain.

Configuring Session
In ASP.NET MVC (just "MVC' from here on in), configuration is handled through a combination of the web.config file, the Global.asax file, and the classes in the files in the Startup folder. In ASP.NET MVC Core (just "MVC Core' from here), all configuration is done in just one place: the Startup class in the project's Startup.cs file.

That's good because there's a lot of configuration to do: You have to pick both which services you want to use and what middleware you want in the ASP.NET processing pipeline. Of course, if you're an MVC developer coming to MVC Core, you want all the processing you're used to from MVC. Fortunately, that's easy to do:

  • In the Startup class's ConfigureServices method, call the AddMvc method on the IServiceCollection object passed to the method (AddMvc makes a default set of services available to your application).
  • In the Configure method, call the UseMvc method on the IApplicationBuilder object passed to the method (that creates a default pipeline for processing requests and responses).
  • Sadly, neither of those will add support for using Session. To add Session support, you're going to add this code to the ConfigureServices method before your call to the AddMvc method:

    services.AddSession(so =>
    {
      so.IdleTimeout = TimeSpan.FromSeconds(60);
    });
    

    Without this code, when you first try to use Session, you'll get a message about "InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Session.ISessionStore'."

    As you can see, the AddSession method accepts a lambda expression that is, in turn, passed a SessionOptions object (I called the object "so" in my sample code). You use the SessionOptions object to set the options you would have set in the sessionState element in an MVC project's web.config file (by the way: passing an options object to a lambda expression is a pattern that you'll see crop up in several of the configuration methods in MVC Core).

    You're now ready to use the Session object ... but it won't be where you're looking for it in your Controller classes: The base Controller class no longer has a Session property.

    The Controller class does have an HttpContext property that returns the HttpContext object and it does have a Session property. You can use the Session object in that property.

    Reading and Writing Session
    Sadly, however, when it comes time to set or retrieve Session values, the wheels really fall off: The Session object no longer has an indexer. Instead, you must use the methods SetString, GetString, SetInt and GetInt to change or retrieve values. One note: Many of these are extension methods so, if at first you don't see them in your IntelliSense list, you may just need to wait a few seconds for them to appear.

    This means that, in MVC Core, the code to add the string "x001" under the key "TransId" looks like this:

    public ActionResult Index()
    {
      this.Session.SetString("TransId", "x001");
    

    Notably absent from the methods available is a SetObject or GetObject method (though there are methods that return byte arrays, as if I cared).

    If you want to save or restore objects, Microsoft's recommendation is to convert them to JSON strings using the NewtonSoft utilities and then use SetString and GetString. Microsoft has even provided sample extension methods for Session that do just that.

    Search-And-Replace Migration
    As you can see, it's not possible, using a global search-and-replace, to migrate MVC Session code that looks like this:

    Session["Trans"] = transact;

    to this code:

    Session.SetObject("Trans", "transact");
    

    But, if you're willing to write some code, you can enable a "global search-and-replace migration." The first step is to create an extension method like the following that will attach itself to the Session object:

    public static SessionIndexer AddIndexer(this ISession session)
    {
      return new SessionIndexer(session);
    }
    

    That SessionIndexer class that's returned from this method provides an indexer that stores values in the Session object passed to the class:

    public class SessionIndexer
    {
      private ISession Session;
      public SessionIndexer(ISession Session)
      {
        this.Session = Session;
      }
      public object this[string key]
      {
        set
        {
          Session.SetObject(key, value);
        }
       get
        {
          return Session.GetObject(key);
        }
      }
    }
    

    With these utilities in place, existing code that looks like this:

    Session["Trans"] = transact;

    can be migrated with a global search-and-replace that finds "Session[" and substitutes "Session.SetIndexer()[":

    Session.AddIndexer()["Trans"] = "transact";
    

    Don't get me wrong: You still don't want to migrate existing MVC applications. Really, you don't. And don't ask me how I know this.

    About the Author

    Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

    comments powered by Disqus

    Featured

    • Hands On: New VS Code Insiders Build Creates Web Page from Image in Seconds

      New Vision support with GitHub Copilot in the latest Visual Studio Code Insiders build takes a user-supplied mockup image and creates a web page from it in seconds, handling all the HTML and CSS.

    • Naive Bayes Regression Using C#

      Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the naive Bayes regression technique, where the goal is to predict a single numeric value. Compared to other machine learning regression techniques, naive Bayes regression is usually less accurate, but is simple, easy to implement and customize, works on both large and small datasets, is highly interpretable, and doesn't require tuning any hyperparameters.

    • VS Code Copilot Previews New GPT-4o AI Code Completion Model

      The 4o upgrade includes additional training on more than 275,000 high-quality public repositories in over 30 popular programming languages, said Microsoft-owned GitHub, which created the original "AI pair programmer" years ago.

    • Microsoft's Rust Embrace Continues with Azure SDK Beta

      "Rust's strong type system and ownership model help prevent common programming errors such as null pointer dereferencing and buffer overflows, leading to more secure and stable code."

    • Xcode IDE from Microsoft Archrival Apple Gets Copilot AI

      Just after expanding the reach of its Copilot AI coding assistant to the open-source Eclipse IDE, Microsoft showcased how it's going even further, providing details about a preview version for the Xcode IDE from archrival Apple.

    Subscribe on YouTube

    Upcoming Training Events