Подтвердить что ты не робот

Как передать параметры в пользовательский ActionFilter в ASP.NET MVC 2?

Я пытаюсь создать собственный ActionFilter, который работает с набором параметров, которые будут переданы ему с контроллера.

Пока мой клиент ActionFilter выглядит так:

public class CheckLoggedIn : ActionFilterAttribute
{
    public IGenesisRepository gr { get; set; }
    public Guid memberGuid { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Member thisMember = gr.GetActiveMember(memberGuid);
        Member bottomMember = gr.GetMemberOnBottom();

        if (thisMember.Role.Tier <= bottomMember.Role.Tier)
        {
            filterContext
                .HttpContext
                .Response
                .RedirectToRoute(new { controller = "Member", action = "Login" });
        }

        base.OnActionExecuting(filterContext);
    }
}

Я знаю, что мне все еще нужно проверять нули и т.д., но я не могу понять, почему gr и memberGuid успешно не передаются. Я вызываю этот фильтр следующим образом:

    [CheckLoggedIn(gr = genesisRepository, memberGuid = md.memberGUID)]
    public ActionResult Home(MemberData md)
    {
        return View(md);
    }

genesisRepository и md устанавливаются в конструкторе контроллера.

Я не могу заставить это скомпилировать. Ошибка, которую я получаю:

Error   1   'gr' is not a valid named attribute argument because it is not a valid attribute parameter type
Error   2   'memberGuid' is not a valid named attribute argument because it is not a valid attribute parameter type

Я дважды проверил, что gr и memberGuid были теми же типами, что и genesisRepority и md.memberGUID, что вызывает эти ошибки?

Решение

Благодаря jfar для предоставления решения.

Здесь фильтр я закончил использование:

public class CheckLoggedIn : ActionFilterAttribute
{

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var thisController = ((MemberController)filterContext.Controller);

        IGenesisRepository gr = thisController.GenesisRepository;
        Guid memberGuid = ((MemberData)filterContext.HttpContext.Session[thisController.MemberKey]).MemberGUID;

        Member thisMember = gr.GetActiveMember(memberGuid);
        Member bottomMember = gr.GetMemberOnBottom();

        if (thisMember.Role.Tier >= bottomMember.Role.Tier)
        {
            filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary(
                    new { 
                        controller = "Member", 
                        action = "Login" 
                    }));
        }

        base.OnActionExecuting(filterContext);
    }
}
4b9b3361

Ответ 1

Это способ сделать эту работу. У вас есть доступ к ControllerContext и, следовательно, к Controller из объекта ActionFilter. Все, что вам нужно сделать, это указать ваш контроллер на тип, и вы можете получить доступ к любым открытым членам.

Учитывая этот контроллер:

public GenesisController : Controller
{
    [CheckLoggedIn()]
    public ActionResult Home(MemberData md)
    {
        return View(md);
    }
}

ActionFilter выглядит примерно как

public class CheckLoggedIn : ActionFilterAttribute
{
    public IGenesisRepository gr { get; set; }
    public Guid memberGuid { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        /* how to get the controller*/
        var controllerUsingThisAttribute = ((GenesisController)filterContext.Controller);

        /* now you can use the public properties from the controller */
        gr = controllerUsingThisAttribute .genesisRepository;
        memberGuid = (controllerUsingThisAttribute .memberGuid;

        Member thisMember = gr.GetActiveMember(memberGuid);
        Member bottomMember = gr.GetMemberOnBottom();

        if (thisMember.Role.Tier <= bottomMember.Role.Tier)
        {
            filterContext
                .HttpContext
                .Response
                .RedirectToRoute(new { controller = "Member", action = "Login" });
        }

        base.OnActionExecuting(filterContext);
    }
}

Конечно, это предполагает, что ActionFilter не используется на нескольких контроллерах, и вы в порядке с муфтой. Другим вариантом является создание интерфейса ICheckedLoggedInController с общими свойствами и просто отбрасывание на него.

Ответ 2

Вы можете использовать только постоянные значения свойств атрибута; см. эту страницу для полного объяснения.

Ответ 3

Атрибуты - это по существу метаданные, добавленные к типу. Они могут использовать значения const вместо переменных экземпляра. В вашем случае вы связываетесь с передачей в своих переменных экземпляра genisisRepository и т.д. Это не скомпилируется, поскольку они не являются константами времени компиляции.

Для этого вы должны изучить "Инъекции зависимостей для Action Action", обычно используя контейнер IoC.

Кроме того, если ActionFilter выполняет действие ActionResult, например OnActionExecuted, возможно, вам удастся сохранить что-то в данных маршрута:

public ActionResult Index()
{
  ControllerContext.RouteData.DataTokens.Add("name", "value");
  return View();
}

Ответ 4

инъекция зависимостей является идеальным решением в этом случае; местоположение службы - это еще один (более простой) вариант для рассмотрения.

Хорошо... Я не уверен, что это возможно. md.memberGUID привязан к сеансу и не может быть константой, потому что сайту потребуется доступ к обновленным данным для входа.

потому что я не хочу создавать зависимость для определенного ключа сеанса. Я бы предпочел, чтобы проверка global.aspx.cs выявила привязку, и будущий разработчик мог легко внести изменения.

Добавление данных в данные маршрута, которые не указаны в URL, является довольно ужасным способом хранения данных. Это приводит к затруднению поиска ошибок. - Injection Dependency на самом деле не помогает решить эту проблему. Любой метод, который предоставляет репозитории ActionFilter, будет работать. Теперь, конечно, DI лучше помочь остановить проблемы с местоположением службы, но это не решение, а лишь один из способов решения проблемы. Хорошая статья о том, как достичь этого: lostechies.com/blogs/jimmy_bogard/archive/2010/05/03/...