Session State Behavior Per Action in ASP.NET MVC

Introduction

The SessionState Attribute helps us to controll the session state behavior in ASP.NET MVC. We can make session state disable / read only / required for controller using this attribute. This is a class level attribute so we can only apply this attribute at the controller level. Some of the action methods of a controller might have a different behavior than the controller session state behavior. In this case the following solution is very useful. So we can apply a session state behavior per action in ASP.NET MVC.

Problem Statement

We can control session state behavior using SessionState attribute but this can only be applied at the controller level. This means that all action methods of the controller have the same session state behavior. Now if some of the action methods of the controller do not use a session and some of action method does use the session then what is solution?

Solution

In this scenario, we can create a different controller and move all the action methods that have the same session state behavior for in the same controller class. This is not a good solution. Instead of doing this we can create a custom action attribute that overwrites the behavior of the session state for the specific action method.

Use the following procedure to create a custom action attribute that overrides the behavior of the session state.

Step 1: Create custom attribute
 

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class ActionSessionStateAttribute : Attribute
{
    public SessionStateBehavior Behavior { get; private set; } 
    public ActionSessionStateAttribute(SessionStateBehavior behavior)
    {
        this.Behavior = behavior;
    }

}

Step 2: Create custom controller factory

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            return SessionStateBehavior.Default;
        }
 
        var actionName = requestContext.RouteData.Values["action"].ToString();
        MethodInfo actionMethodInfo;
        actionMethodInfo = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
        if (actionMethodInfo != null)
        {
            var actionSessionStateAttr = actionMethodInfo.GetCustomAttributes(typeof(ActionSessionStateAttribute), false)
                                .OfType<ActionSessionStateAttribute>()
                                .FirstOrDefault();
 
            if (actionSessionStateAttr != null)
            {
                return actionSessionStateAttr.Behavior;
            }
        }
        return base.GetControllerSessionBehavior(requestContext, controllerType);
    }
}

Step 3: Register custom controller factory in Global.asax

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
    ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
}

Step 4: Attribute usages

[SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)]

public class HomeController : Controller

{

    public ActionResult Index()

    {

        ViewBag.Message = "Welcome to ASP.NET MVC!";

        TempData["test"] = "session less controller test";

        return View();

    }

 

    [ActionSessionState(System.Web.SessionState.SessionStateBehavior.Required)]

    public ActionResult About()

    {

        Session["test"] = "session less controller test";

        return View();

    }

}

The following is the output when the “Index” action method is called:

action method

The following is the output when the “About” is called:
 
About action method

Conclusion

We can use the ActionSessionStateAttribute in combination with the controller level attribute SessionStateAttribute, in this case use the ActionSessionStateAttribute overwrite controller attribute on the actions to which it applies.