ActionSelectorを使用してActionの選択を制御する


ActionFilterはMVC制御の中でAction制御の中で最も研究に値するものに違いない.プロジェクトの実際には避けられない使用例:
  • HandleError
  • Authorized
  • OutputCache

  • 本稿では,Action Selector方式を用いてActionの選択を行い,この問題を明らかにするために,実際の問題から注目する.

    実際の問題は趙さんとの会話から分かる。


    Admin、Client、Agentなど、システムには異なる役割があります.Book/Listという機能があると仮定すると、1つのListのようなViewとactionがListのようなBookControllerに対応し、現在、我々の場合は異なるキャラクターに対して対応するListが異なる.Adminが見たBook/ListとClientが見たBook/Listは違うのでUrl:http://anytao.com/Book/List/123あ、キャラによってどのように扱われているのか、差は少ないですが、このまま、はっきりしているかどうか.
    私:では、同じActionに対してどのように異なるviewにreturnをもっと良くしますか?
    趙さん:具体的な問題は何ですか.
    私:私が今考えているのは、ActionではロールReturnから異なるViewまで、簡単な方法はList ActionでロールReturnから異なるViewまでです.問題は、もっと良い方法があるということです.
    趙さん:n各actionを用意して、それぞれ自分で決めたActionSelectorを加えて、1つのActionを使わないで、1つのActionを使わないで、中にifを入れます.
    [OnlyInRole("admin")] 
    [ActionName("List")]
    ListForAdmin() 
    {
    }
    
    [OnlyInRole("user")] 
    [ActionName("List")]
    ListForUser() 
    {
    }

    OnlyInRoleは自分で書く必要がありますが、数行だけです.
    私:ははは、差は多くありません.ありがとうございます.
    趙さんの指導によって、私はこの構想に対して必要な検討を行って、やはり凡響とは違って、とても暴力的だと感じました.

    ソリューション


    Actionに対するSelectorの具体的な実装を実現するために、私はActionNameSelectorAttributeを拡張することを選択し、ActionNameの実装方式を参照し、RoleTypeによるフィルタリングの需要に対して明らかに良い参考価値があり、ActionNameAttributeを例にとると、その具体は以下のように実現される.
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public sealed class ActionNameAttribute : ActionNameSelectorAttribute {
    
        public ActionNameAttribute(string name) {
            if (String.IsNullOrEmpty(name)) {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "name");
            }
    
            Name = name;
        }
    
        public string Name {
            get;
            private set;
        }
    
        public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
            return String.Equals(actionName, Name, StringComparison.OrdinalIgnoreCase);
        }
    
    }

    さらに、ActionNameSelectorAttribute抽象クラスの定義について説明します.主にActionに対してSelectを行う際のIsValidName判定規則、例えばActionNameSelectorAttributeの定義を提供します.
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public abstract class ActionNameSelectorAttribute : Attribute {
        public abstract bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo);
    }

    したがって、A n t i n A m e SelecterAttributeの拡張は非常に簡単になりました.以下は最も簡単な実装です.
    // Release : code01, 2009/04/17                    
    // Author  : Anytao, http://www.anytao.com
    public class ActionInRoleAttribute : ActionNameSelectorAttribute
    {
        public ActionInRoleAttribute(RoleType role)
        {
            this.role = role;
        }
    
        public override bool IsValidName(ControllerContext controllerContext, string actionName, System.Reflection.MethodInfo methodInfo)
        {
            if (controllerContext.HttpContext.User.IsInRole(role.ToString()))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    
        private RoleType role;
    }

    私たちの論理は実は簡単で、IPrincipalのIsInRole方法を借りて、roleの定義に基づいてIsValidNameフィルタリングを簡単に行うことができます.例えば、私たちは次のようにすることができます.
    // Release : code02, 2009/04/17                    
    // Author  : Anytao, http://www.anytao.com
    [AcceptVerbs(HttpVerbs.Get)]
    [ActionName("List")]
    [ActionInRole(RoleType.Client)]
    public ActionResult ClientList(int id)
    {
        return View(
            "ClientBookList",
            new Book
            {
                ID = id,
                Name = string.Empty
            });
    }
    
    // Release : code03, 2009/04/17                    
    // Author  : Anytao, http://www.anytao.com
    [AcceptVerbs(HttpVerbs.Get)]
    [ActionName("List")]
    [ActionInRole(RoleType.Admin)]
    public ActionResult AdminList(int id)
    {
        return View(
            "AdminBookList",
            new Book
            {
                ID = id,
                Name = string.Empty
            });
    }

    List Actionが呼び出されると、登録ユーザの役割に応じて具体的に実行されるAction(ClientListまたはAdminList)が決定され、異なるActionによって異なるView(ClientBookListまたはAdminBookList)にナビゲートされ、異なるActionに対してアクセスするURLは同じ(http://anytao.com/Book/List/123)は、同時にサービス層での役割の判断を回避し、ある程度RoleTypeに従ってController層に「注入」を行い、Controller層の論理がActionフィルタリングの問題に関心を持たないようにした.
    しかし、アプリケーションにはいくつかの注意すべき問題があります.
  • 非汎用ActionLinkメソッドを使用してアプリケーションActionInRoleのAction
  • を呼び出す.
    一般的に、強いタイプのModelDataを適用してViewレイヤで操作することを提唱していますが、汎用的な方法ActionLinkは推奨されます.
    <p>
        = Html.ActionLink<BookController>(c => c.List(Model.ID), "List") %>
    p>

    しかし、アプリケーションがActionInRoleによってマークされ、ActionNameによって名前が変更されたActionは認識されず、マルチアクティブなActionに対して呼び出される非汎用的な方法で実現するしかありません.
    <p>
        = Html.ActionLink("List", "List", new { id=Model.ID }) %>
    p>
  • return Viewでは、ViewNameを作成して戻ることによって、
  • などの適切なViewを選択します.
    return View(
        "AdminBookList",
        new Book
        {
            ID = id,
            Name = string.Empty
        });

    デフォルトではMVCエンジンはActionNameで返されるので、私たちのアプリケーションではこのような方法で行わなければなりません.

    結論


    本稿では,特にActionFilterとは何かを検討することなく応用に重点を置き,適切な時間にMVCと再び握手し,これについてさらに議論する.
    変換元:
    http://www.cnblogs.com/anytao/archive/2009/04/22/anytao-mvc-01-actioninrole.html