A Better Approach To Access HttpContext Outside A Controller In .Net Core 2.1

In this approach, we are going to create a static AppContext class. This class is going to hold the current Http session as a property called Current.

Introduction

In my previous article, we discussed an approach to access the HttpContext.Session in a RequestHandler outside our Homecontroller. However, there was a problem. For every single component where we need to access the session, we have to inject a dependency of IHttpContextAccessor. While it's not a problem for one or two components, it can be very daunting if we have to do the same over and over again. In this article, we will use a different approach to achieve the same.

The AppContext

In this approach, we are going to create a static AppContext class. This class is going to hold the current Http session as a property called Current. Previously, we used the IHttpContextAccessor to get the current Http session, likewise we are going to do that here. However, since I want to keep the AppContext static, we need a static method to inject IHttpContextAccessor to it, as shown in the code below,

  1. using Microsoft.AspNetCore.Http;  
  2.   
  3. namespace StaticHttpContextAccessor.Helpers  
  4. {  
  5.     public static class AppContext  
  6.     {  
  7.         private static IHttpContextAccessor _httpContextAccessor;  
  8.   
  9.         public static void Configure(IHttpContextAccessor httpContextAccessor)  
  10.         {  
  11.             _httpContextAccessor = httpContextAccessor;  
  12.         }  
  13.   
  14.         public static HttpContext Current => _httpContextAccessor.HttpContext;  
  15.     }  
  16. }  
The Startup Class 

The Startup class in this case will be a little different from the previous one. We still need to add the IHttpContextAccessor to the ConfigureServices method. It is the ConfigureService method where we will inject the IHttpContextAccessor into the AppContext. And, to achieve that we are going to use the IApplicationBuilder as shown below,

  1. using Microsoft.AspNetCore.Builder;  
  2. using Microsoft.AspNetCore.Hosting;  
  3. using Microsoft.AspNetCore.Http;  
  4. using Microsoft.AspNetCore.Mvc;  
  5. using Microsoft.Extensions.Configuration;  
  6. using Microsoft.Extensions.DependencyInjection;  
  7. using StaticHttpContextAccessor.Helpers;  
  8.   
  9. namespace StaticHttpContextAccessor  
  10. {  
  11.     public class Startup  
  12.     {  
  13.         public Startup(IConfiguration configuration) { Configuration = configuration; }  
  14.         public IConfiguration Configuration { get; }  
  15.   
  16.         public void ConfigureServices(IServiceCollection services)  
  17.         {  
  18.             services.Configure<CookiePolicyOptions>(options => {  
  19.                 options.CheckConsentNeeded = context => true;  
  20.                 options.MinimumSameSitePolicy = SameSiteMode.None;  
  21.             });  
  22.   
  23.             services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);  
  24.             services.AddSession();  
  25.             services.AddHttpContextAccessor();  
  26.             services.AddSingleton<RequestHandler>();  
  27.         }  
  28.   
  29.         public void Configure(IApplicationBuilder app, IHostingEnvironment env)  
  30.         {  
  31.             if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); }  
  32.             else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); }  
  33.             app.UseHttpsRedirection();  
  34.             app.UseCookiePolicy();  
  35.   
  36.             app.UseSession();  
  37.             AppContext.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>());  
  38.   
  39.             app.UseMvc(routes =>  
  40.             {  
  41.                 routes.MapRoute(  
  42.                     name: "default",  
  43.                     template: "{controller=Home}/{action=Index}/{id?}");  
  44.             });  
  45.         }  
  46.     }  
  47. }  
ISession Extensions

Just for fun, I added a few extension methods for ISession though it's not really required. But if you find them useful, go ahead to consume them in a real life project,

  1. using Microsoft.AspNetCore.Http;  
  2. using Newtonsoft.Json;  
  3.   
  4. namespace StaticHttpContextAccessor.Helpers  
  5. {  
  6.     public static class HttpSessionHelper  
  7.     {  
  8.         public static void Set<T>(this ISession session, string key, T value)  
  9.         {  
  10.             session.SetString(key, JsonConvert.SerializeObject(value));  
  11.         }  
  12.   
  13.         public static T Get<T>(this ISession session, string key)  
  14.         {  
  15.             var value = session.GetString(key);  
  16.             return value == null ? default(T) :  
  17.                 JsonConvert.DeserializeObject<T>(value);  
  18.         }  
  19.     }  
  20. }  
The RequestHandler and HomeController

Now that we have the setup ready, it's time to set the message in our RequestHandler using the AppContext which gives us the current session. We can then get the mesage from the session in the controller, as we did in our previous approach. Please refer to the code below,

  1. namespace StaticHttpContextAccessor.Helpers  
  2. {  
  3.     public class RequestHandler  
  4.     {  
  5.         public void HandleIndexRequest()  
  6.         {  
  7.             // do something for the request  
  8.   
  9.             var message = "This is a much cleaner approach to access Session!";  
  10.             AppContext.Current.Session.Set<string>("message", message);  
  11.         }  
  12.     }  
  13. }  
  1. using Microsoft.AspNetCore.Mvc;  
  2. using StaticHttpContextAccessor.Helpers;  
  3.   
  4. namespace StaticHttpContextAccessor.Controllers  
  5. {  
  6.     public class HomeController : Controller  
  7.     {  
  8.         private readonly RequestHandler _requestHandler;  
  9.   
  10.         public HomeController(RequestHandler requestHandler)  
  11.         {  
  12.             _requestHandler = requestHandler;  
  13.         }  
  14.   
  15.         public IActionResult Index()  
  16.         {  
  17.             _requestHandler.HandleIndexRequest();  
  18.             ViewData["Message"] = HttpContext.Session.Get<string>("message");  
  19.             return View();  
  20.         }  
  21.     }  
  22. }  
Summary

If I compare this approach with the previous one, this one feels much cleaner. I would be more than happy to know what you guys think about the two. Which one would you choose and why? Please do let me know in the comments below.

If you have not read my previous article discussing the first approach, you can find the same at: Using HttpContext Outside An MVC Controller In .Net Core 2.1