Search code examples
c#asp.net-mvc-4action-filter

ASP.NET MVC4 ActionFilters


I have an ASP.NET MVC4 application. I created a Login page. If a user log in to the system, I register user's information in to session. I added a filter for checking session variable. If user didn't log in to the system, I want to redirect user to my login controller.

public class SecurityAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.Session["User"] == null)
            {
                filterContext.HttpContext.Response.RedirectToRoute("Default", new
                {
                    controller = "Login",
                    action = "DoLogin",
                    returnUrl = filterContext.HttpContext.Request.Url.AbsoluteUri
                });
            }
            base.OnActionExecuting(filterContext);
        }
    }

I am using this attribute at controller level.

[SecurityAttribute]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewData["Name"] = ((UserEntity)Session["User"]).Name;
            ViewData["Surname"] = ((UserEntity)Session["User"]).Surname;
            return View();
        }
    }

OnActionExecuting method fires before action executing, but redirect occures after action method in my home controller. Because session variable is null, I get an error in index action. How can I fix this?


Solution

  • You should assign the Result property on the filterContext if you want to short-circuit the execution of the controller action. Just like that:

    public class SecurityAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.Session["User"] == null)
            {
                var values = new
                {
                    controller = "Login",
                    action = "DoLogin",
                    returnUrl = filterContext.HttpContext.Request.Url.AbsoluteUri
                };
                var result = new RedirectToRouteResult("Default", new RouteValueDictionary(values));
    
                filterContext.Result = result;
            }
        }
    }
    

    Also it would have been semantically more correct to write an authorization filter for that purpose and rely on the built-in Forms Authentication rather than reinventing wheels with Session and stuff.

    So simply:

    [Authorize]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            string username = User.Identity.Name;
            SomeUserModel user = GetUserFromBackend(username);
            return View(user);
        }
    }
    

    You can read more about Forms Authentication at MSDN: http://msdn.microsoft.com/en-us/library/ff647070.aspx