web-dev-qa-db-ja.com

ASP.NET MVC 2のカスタムActionFilterにパラメータを渡す方法は?

コントローラーから渡される一連のパラメーターを操作するカスタム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

grおよびmemberGuidgenesisReporityおよび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);
    }
}
31
quakkels

これは、この機能を実現する方法です。 ControllerFilterにアクセスできるため、ActionFilterオブジェクトから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インターフェイスを作成し、代わりに単純にキャストすることです。

33
John Farrell

属性プロパティには定数値のみを使用できます。完全な説明については、 このページ を参照してください。

8
DanP

属性は、本質的に型に追加されるメタデータです。インスタンス変数の代わりに、const値のみを使用できます。あなたの場合、あなたはgenisisRepositoryなどのインスタンス変数を渡そうとしています。これらはコンパイル時定数ではないため、コンパイルに失敗します。

これを実現するには、通常はIoCコンテナーを使用して、アクションフィルターの依存性注入を調べる必要があります。

また、ActionFilterがOnActionExecutedなどのPostActionResultアクションを実行している場合、おそらくルートデータに何かを保存することで回避できます。

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