Search code examples
c#sessionasp.net-core-mvchttpcontext

How can I make a session variable available to all controllers without accessing HttpContext in each controller?


I'm trying to make the int variable BranchId available through out my application via the use of HttpContext.Session.GetInt32("BranchId").Value.

As I gather from my own attempt, and from the answer to this question, this approach will not work:

Base controller class:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace Vaktliste.Controllers
{
    public class MyBaseControllerClass : Controller
    {
        public readonly int branchId;

        public MyBaseControllerClass()
        {
            var s = HttpContext.Session; // <-- This causes a NULL exception
            // SET THE VARIABLE HERE:
            BranchId = s.GetInt32("BranchId") != null
                ? s.GetInt32("BranchId").Value
                : 0;
        }
    }
}

Example of another controller in the application:

namespace Vaktliste.Controllers
{
    public class BranchesController : MyBaseControllerClass
    {
        private readonly VaktlisteContext db;

        public BranchesController(VaktlisteContext context)
        {
            db = context;
        }

        public async Task<IActionResult> Details(int? id)
        {
            // USE THE VARIABLE HERE:
            if (id == null) id = BranchId;

            if (id == null) return NotFound();

            var branch = await db.Branches
                .Where(m => m.Id == id)
                .FirstOrDefaultAsync();

            if (branch == null) return NotFound();

            HttpContext.Session.SetInt32("BranchId", branch.Id);

            return View(branch);
        }
    }
}

I could of course do the GetInt32("BranchId") in every controller, but I want to keep it DRY (Don't Repeat Yourself). How can it be done?


Solution

  • Perhaps you can achieve this with a property. When the basecontroller is created, the httpcontext.session is null. If you use a property and only access it in your routes, the session should be available.

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    
    namespace Vaktliste.Controllers
    {
        public class MyBaseControllerClass : Controller
        {
            public readonly int branchId;
            protected int BranchId { 
                get { HttpContext.Session?.GetInt32("BranchId")?.Value ?? 0; }
                set { HttpContext.Session.SetInt32("BranchId", value); }
            }
    
            public MyBaseControllerClass()
            {
    
            }
        }
    }
    

    Then just access the property to get the value

    namespace Vaktliste.Controllers
    {
        public class BranchesController : MyBaseControllerClass
        {
            private readonly VaktlisteContext db;
    
            public BranchesController(VaktlisteContext context)
            {
                db = context;
            }
    
            public async Task<IActionResult> Details(int? id)
            {
                // USE THE VARIABLE HERE:
                id = id ?? BranchId;
    
                if (id == null) return NotFound();
    
                var branch = await db.Branches
                    .Where(m => m.Id == id)
                    .FirstOrDefaultAsync();
    
                if (branch == null) return NotFound();
    
                BranchId = branch.Id;
    
                return View(branch);
            }
        }
    }