打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
[一步一步MVC]第一回:使用ActionSelector控制Action的选择

《你必须知道的.NET》网站 | Anytao技术博客 | anytao.net


发布日期:2009.04.21  作者:Anytao
2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处。


ActionFilter一定是MVC控制中对于Action控制中最值得研究的玩意,在项目实际中我们不可避免的使用例如:



  • HandleError

  • Authorized

  • OutputCache


在本文中,我们应用Action Selector方式进行Action的选择,想要阐述清楚这个问题,我们从实际的问题出发来关注。


实际的问题,从和老赵的对话了解


我们有个业务室这样的:系统有不同的角色,例如Admin、Client、Agent。假设有个功能叫Book/List,那么就对应了一个List这样的View和action为List这样的BookController,现在,我们的情况是对于不同的角色,所对应的List是不同的。Admin看到的Book/List和Client看到的Book/List是不同的,那么通过Url:http://anytao.com/Book/List/123,不同的角色如何处理,差不多就这样,是否清楚。


:那么对于同一Action如何更好的return到不同的view?


老赵:具体问题是什么呢?


: 我现在能想到的是在Action中根据角色Return到不同的View,简单的办法就是在List Action根据角色Return到不同的View。问题是,还有什么更好的办法。


老赵:准备n各action,分别加上自定的ActionSelector,不要用一个Action,不用一个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);}


所以,对ActionNameSelecterAttribute进行扩展变得异常简单,下面是一个最简单的实现,肯定让我们耳目一新:



// Release : code01, 2009/04/17                    // Author  : Anytao, http://www.anytao.compublic 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握手,对此进行进一步进行讨论。


 



更多关注,尽在anytao.net/blog


 


特别鸣谢:



  • 老赵,该方案是老赵MSN提议的解决方案,经实际测试果然名不虚传,故做此文以济之。


支持anytao的创业产品Worktile

Worktile,新一代简单好用、体验极致的团队协同、项目管理工具,让你和你的团队随时随地一起工作。完全免费,现在就去了解一下吧。

https://worktile.com
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
mvc基础系列说谈(3)——controller与action
ASP.NET MVC 流程概述(转)
[ASP.NET MVC 小牛之路]10 - Controller 和 Action (2)
[你必须知道的.NET] 第五回:深入浅出关键字---把new说透
整理下Anytao《你必须知道的.Net》全文链接
白话学习MVC(六)模型绑定
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服