40

我正在尝试创建一个自定义 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);
    }

genesisRepositorymd在控制器的构造函数中设置。

我无法编译它。我得到的错误是:

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

我仔细检查了一下grmemberGuid它们的类型与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);
    }
}
4

3 回答 3

38

This is a way to make this work. You have access to the ControllerContext and therefore Controller from the ActionFilter object. All you need to do is cast your controller to the type and you can access any public members.

Given this controller:

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

ActionFilter looks something like

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

Of course this is assuming the ActionFilter isn't used across multiple controllers and you're ok with the coupling. Another Option is to make a ICheckedLoggedInController interface with the shared properties and simply cast to that instead.

于 2010-12-03T17:34:14.313 回答
8

您只能对属性属性使用常量值;有关完整说明,请参阅此页面

于 2010-12-03T17:20:56.937 回答
4

属性本质上是添加到类型的元数据。它们只能使用const值,而不是实例变量。在您的情况下,您要传递genisisRepository等的实例变量。这将无法编译,因为它们不是编译时常量。

您应该研究动作过滤器的依赖注入来实现这一点,通常使用 IoC 容器。

此外,如果您的 ActionFilter 正在执行 post ActionResult 操作,例如OnActionExecuted,您可能会在路由数据中存储一些内容:

public ActionResult Index()
{
  ControllerContext.RouteData.DataTokens.Add("name", "value");
  return View();
}
于 2010-12-03T17:22:37.977 回答