Session is a useful tool for storing user data while the user browses a web app. When the session expires, the user needs to be logged out and redirected to a different page. With good old ASP.NET, there is an event called Session_End
that is triggered whenever the session terminates. Unfortunately, .NET Core doesn’t have such things and we have to handle it ourselves.
Theoretically, one could detect the session expiration by checking the session value of a specific key at the beginning of every action method. However, that would be cumbersome and make the code too repetitive. One clean approach that I find to be efficient and easy to implement is to use action filters. To put it simple, action filters run immediately before and after an action method is called (Source: Microsoft Learn). We can utilize this feature to have the action filter to check the session validation for us ahead of the execution of targeted actions. Now let’s get started.
First, add session to your ASP.NET Core MVC web app if you haven’t already. Specifically, add builder.services.AddSession()
and app.UserSession()
to Program.cs file.
Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddSession();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSession();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Next, create a filters folder in the project root directory. Inside the folder, create a new class SessionExpireAttribute
that inherits from ActionFilterAttributes
, then add a method OnActionExecuting
to the class. This method checks if the session value with the key username is null or empty. If so, it means that the session has expired, and the route will be redirected to the Login action of Auth controller.
SessionExpireAttribute.cs:
public class SessionExpireAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var username = context.HttpContext.Session.GetString("username");
if (string.IsNullOrEmpty(username))
context.Result =
new RedirectToRouteResult(
new RouteValueDictionary(
new { action = "Login", controller = "Account"}));
}
}
The project structure with the action filter included is shown below:
Now we just need to add the SessionExpire
attribute to actions/controllers that need to perform session timeout check to invoke the action filter. This attribute can be applied to either an action method or a controller. When the attribute is placed at the controller, the action filter will take effect on all actions inside the controller.
In the example below, when the SessionExpire
attribute is placed at the controller, all actions inside the controller will execute the action filter.
Example of attribute placed at the controller:
[SessionExpire]
public class HomeController : Controller
{
// Index() will execute the action filter
public IActionResult Index()
{
}
// Privacy() will execute the action filter
public IActionResult Privacy()
{
}
}
In contrast, when the SessionExpire
attribute is placed at a specific action method, only that action method will execute the action filter.
Example of attribute placed at an action method:
public class HomeController : Controller
{
// Index() will execute the action filter
[SessionExpire]
public IActionResult Index()
{
}
// Privacy() will NOT execute the action filter
public IActionResult Privacy()
{
}
}
That’s it! Please leave a comment blow if you have any thoughts.