如何将参数传递给ASP.NET MVC 2中的自定义ActionFilter?

时间:2010-12-03 17:16:58

标签: c# asp.net asp.net-mvc action-filter

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

我知道我仍然需要检查空值等,但我无法弄清楚为什么grmemberGuid未成功传递。我把这个过滤器称为:

    [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

我仔细检查grmemberGuidgenesisReporitymd.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);
    }
}

3 个答案:

答案 0 :(得分:33)

这是一种使这项工作的方法。您可以从ActionFilter对象访问ControllerContext,从而访问Controller。您需要做的就是将控制器转换为类型,您可以访问任何公共成员。

鉴于此控制器:

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接口,然后简单地转换为该接口。

答案 1 :(得分:8)

您只能对属性属性使用常量值;请参阅this page获取完整说明。

答案 2 :(得分:3)

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

您应该查看动作过滤器的依赖注入以实现此目的,通常使用IoC容器。

此外,如果你的ActionFilter正在执行一个ActionResult后期操作,例如OnActionExecuted,你可能会在路径数据中存储一些内容:

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