Как передать переменную из ActionFilter в действие контроллера в C# MVC?

Использование простого фильтра действий, который проверяет, вошел ли пользователь в систему, и извлекает его идентификатор пользователя.

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?
        .....
    }
}

Как я могу передать этот идентификатор моему действию контроллера?

[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, который позволил бы мне это сделать? Или какой-то другой метод, который позволяет мне передавать переменные и объекты между фильтром и действием контроллера?


person Jon Story    schedule 09.08.2016    source источник


Ответы (4)


Вы можете использовать ViewData/ViewBag следующим образом:

1.) Использование ViewData

ПРИМЕЧАНИЕ. В случае ViewData вам нужно сделать один шаг, то есть вы должны привести его к типу.

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);
    }
}

А затем в функции контроллера

[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.) Использование 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; 
    }
}

А потом в контроллере

[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;
    }
}
person KAMAL    schedule 09.08.2016
comment
Спасибо, хотя я в конечном итоге использовал TempData (как было предложено в ответе @luiso), а не ViewBag или ViewData, ваш дает наилучшую информацию о том, как его использовать, вместе с примерами, и метод тот же для ViewBag, что и для TempData. Я полагаю, что это Temporary Data, а не что-либо, предназначенное для View, поэтому логичнее использовать TempData. - person Jon Story; 10.08.2016

Я считаю, что ActionExecutingContext содержит ссылку на вызывающий контроллер. Использование этого в сочетании с пользовательским классом контроллера, полученным из базового класса Controller, для последующего сохранения id в качестве переменной экземпляра контроллера, вероятно, сделает это.

Пользовательский контроллер

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

ЛогинФильтр

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)
    }
}

Контроллер

[LoginFilter]
public class Dashboard : MyController
{
    public ActionResult Index()
    {
        //Read the Id here
        int id = this.Id
    }
}
person Francis Lord    schedule 09.08.2016
comment
Мне нравится логика этого решения в том смысле, что оно помещает идентификатор непосредственно в контроллер и довольно аккуратно, но я решил не использовать его, потому что фактическая реализация кажется немного непрозрачной для тех, кто позже поддерживает код - идентификатор просто кажется быть волшебным образом установлен без объяснения причин. - person Jon Story; 10.08.2016
comment
Если мы хотим пройти путь 100% безгражданства, то мы должны выбрать этот путь. +1 голос за ваше хорошее решение @Francis Lord. Спасибо. - person Frank Myat Thu; 17.09.2018

Вы можете использовать ViewBag, выполнив:

filterContext.Controller.ViewBag.Id = id;

это должно сделать это, как только вы сделаете filterContext.Controller, у вас будет доступ ко всем полям внутри него, например, TempData.

Тем не менее, если вы используете OWIN, то, возможно, для получения идентификатора пользователя вы можете использовать Controller.User, у которого есть метод расширения для получения Id и свойств для получения большинства других стандартных данных, таких как Name и т. д.

person Luiso    schedule 09.08.2016
comment
Хм, это кажется изящным решением. Логически использование ViewBag, вероятно, не имеет смысла: но TempData, вероятно, является для него подходящим местом. Я не использую OWIN (по крайней мере, не для этой части проекта, так как мы смешиваем методы аутентификации) - person Jon Story; 09.08.2016

Это метод, который я видел в более старом приложении, избегает использования viewbag и вместо этого заставляет параметры контроллера указывать то, что они ожидают:

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
        ...
    }
}
person Lovethenakedgun    schedule 17.12.2020