9
votes

Taking a simple action filter, which checks if the user is logged in and retrieves their user ID.

public class LoginFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {    
        // Authenticate (somehow) and retrieve the ID
        int id = Authentication.SomeMethod();
        // Pass the ID through to the controller?
        .....
    }
}

How could I then pass this ID through to my controller action?

[LoginFilter]
public class Dashboard : Controller
{
    public ActionResult Index()
    {
        // I'd like to be able to use the ID from the LoginFilter here
        int id = ....
    }
}

Is there an equivalent to the ViewBag that would allow me to do this? Or some other technique that allows me to pass variables and objects between the filter and the controller action?

4

4 Answers

9
votes

You can use ViewData/ViewBag like this:

1.) Using ViewData

NOTE: In case of ViewData you need to do one step that is you have to typecast it

public class LoginFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {    
        // Authenticate (somehow) and retrieve the ID
        int idValue = Authentication.SomeMethod();

        // Pass the ID through to the controller?
        filterContext.Controller.ViewData.Add("Id", idValue);
    }
}

And then in Controller function

[LoginFilter]
public class Dashboard : Controller
{
    public ActionResult Index()
    {
        // I'd like to be able to use the ID from the LoginFilter here
        int id = (int)ViewData["Id"];
    }
}

2.) Using ViewBag

public class LoginFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {    
        // Authenticate (somehow) and retrieve the ID
        int idValue = Authentication.SomeMethod();

        // Pass the ID through to the controller?

        filterContext.Controller.ViewBag.Id = idValue; 
    }
}

And then in controller

[LoginFilter]
public class Dashboard : Controller
{
    public ActionResult Index()
    {
        // I'd like to be able to use the ID from the LoginFilter here
        int id = ViewBag.Id;
    }
}
10
votes

I believe ActionExecutingContext contains a reference to the calling controller. Using this mixed with a custom controller class derived from the base Controller class to then store the id as an instance variable of the controller would probably do it.

Custom controller

Public Class MyController : Controller
{
    Public int Id {get;set;}
}

LoginFilter

public class LoginFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {    
        // Authenticate (somehow) and retrieve the ID
        int id = Authentication.SomeMethod();
        ((MyController)filterContext.Controller).Id = id; 
        //Assign the Id by casting the controller (you might want to add a if ... is MyController before casting)
    }
}

Controller

[LoginFilter]
public class Dashboard : MyController
{
    public ActionResult Index()
    {
        //Read the Id here
        int id = this.Id
    }
}
7
votes

You can use the ViewBag by doing:

filterContext.Controller.ViewBag.Id = id;

that should do it, once you do filterContext.Controller you have access to all fields inside it like TempData as well.

Even so, if you are using OWIN then perhaps to get a user's id you could use the Controller.User which has an extension method to get the Id and properties to get most other standard data like Name etc.

2
votes

This is a method I've seen in an older application, avoids the use of viewbag & instead makes the controller parameters specify what they're expecting:

public class LoginFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {    
        // Authenticate (somehow) and retrieve the ID
        int id = Authentication.SomeMethod();
        
        // Check if there's an action parameter on the controller: set it to your ID
        if (filterContext.ActionParameters.ContainsKey("authId"))
        {
            filterContext.ActionParameters["authId"] = id;
        }
    }
}

[LoginFilter]
public class Dashboard : Controller
{
    public ActionResult Index(int authId)
    {
        // authId parameter is available to each action bearing LoginFilter
        // It's instantiated if it's present in the method signature
        ...
    }
}