asp.net mvc的Routing、Controller、Filter学习笔记

来源:互联网 发布:淘宝助理如何批量下架 编辑:程序博客网 时间:2024/05/21 17:33

1、深入学习Routing

首先Routing的处于的位置,一个Http请求过来,Web容器接收到以后,将信息交给Routing(路由组件),Routing再进行处理~那么Routing的作用

确定Controller确定Action确定其他参数根据识别出来的数据, 将请求传递给Controller和Action.

小提示:asp.net mvc预览版的时候,Routing组件还是作为asp.net mvc的一部分,后续的版本似乎就微软将其编译成一个独立的组件提供System.Web.Routing.dll,也就是说asp.net mvc项目是开源的,但是Routing组件并没有开源。Routing组件不仅在asp.net mvc中可以使用,也可以在WebForm中使用

首先我们新建一个asp.net mvc2/3的项目,新建好以后,直接运行为什么访问localhost/home/index会传递给 HomeController中名为index的action(即HomeController类中的index方法)?怎么实现的呢?
在我们新建的项目中,Global.asax文件中有以下方法
注册路由
       public static void RegisterRoutes(RouteCollection routes)        {            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");            routes.MapRoute(                "Default", // Route name                "{controller}/{action}/{id}", // URL with parameters                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults            );        }

Routes是Application级别(全局)的,在Application开始的时候,程序注册路由,新建的项目默认只注册了一条路由,看下代码,

     routes.MapRoute(
     "Default", // Route name
     "{controller}/{action}/{id}", // URL with parameters
     new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
     );

MapRoute第一个参数是此路由的名称,第二个参数是URL的参数形式,{controller}相当于是一个string.Format方法中的占位符,意思是这里可以是任意一个controller名称,

同理,action、id也是一样的,那为什么请求的/Home/Index并没有Id这个参数,第三个参数是路由规则默认值,这条路由默认的controller是home,action是index,而id呢,是可选的~~~当我们请求/Home/Index的时候,会被此路由获取,而我们直接请求http://localhost的时候,可以到Home/Index的时候,路由参数有默认值

 Ok,到这里我们学习了如何注册路由,我们来试着自己写一条路由

自定义路由
       routes.IgnoreRoute("{resource}.axd/{*pathInfo}");            //自定义路由,            routes.MapRoute(                "myRoute", // Route name                "{controller}-{action}", // URL with parameters                new { controller = "Home", action = "Index" } // Parameter defaults            );            routes.MapRoute(                "Default", // Route name                "{controller}/{action}/{id}", // URL with parameters                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults            );

然后重新启动程序,因为Routes是Application级别的,在我们修改Application级别信息后,应该退出,否则不会有效果滴,这个是好多初学者容易犯错的地方.如果是生产环境,应该重新启动下Web容器.

我们运行程序以后,请求域名/home-index一样可以请求页面,说明我们自定义的路由有效.

这里路由的规则非常灵活,我们可以自定义,以下的路由规则都可以

     routes.MapRoute(
     "myRoute", // Route name
     "{controller}-{action}-{1}-{2}-{3}", // URL with parameters
     new { controller = "Home", action = "Index" } // Parameter defaults
     );

 

MapRoute()方法

MapRoute有以下的重载方法

MapRoute( string name, string url);

MapRoute( string name, string url, object defaults);

MapRoute( string name, string url, string[] namespaces);

MapRoute( string name, string url, object defaults, object constraints);

MapRoute( string name, string url, object defaults, string[] namespaces);

MapRoute( string name, string url, object defaults, object constraints, string[] namespaces);

name参数: 规则名称, 可以随意起名.不可以重名,否则会发生错误: 路由集合中已经存在名为“Default”的路由。路由名必须是唯一的。

url参数: url获取数据的规则, 这里不是正则表达式,  将要识别的参数括起来即可, 比如: {controller}/{action} 最少只需要传递name和url参数就可以建立一条Routing(路由)规则.比如实例中的规则完全可以改为: routes.MapRoute( "Default", "{controller}/{action}");

defaults参数: url参数的默认值.如果一个url只有controller: localhost/home/ 而且我们只建立了一条url获取数据规则: {controller}/{action} 那么这时就会为action参数设置defaults参数中规定的默认值. defaults参数是Object类型,所以可以传递一个匿名类型来初始化默认值: new { controller = "Home", action = "Index" } 实例中使用的是三个参数的MapRoute方法: routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = "" } // Parameter defaults );

constraints参数: 用来限定每个参数的规则或Http请求的类型.constraints属性是一个RouteValueDictionary对象,也就是一个字典表, 但是这个字典表的值可以有两种: 用于定义正则表达式的字符串。正则表达式不区分大小写。 一个用于实现 IRouteConstraint 接口且包含 Match 方法的对象。 通过使用正则表达式可以规定参数格式,比如controller参数只能为4位数字: new { controller = @"\d{4}"}

  通过第IRouteConstraint 接口目前可以限制请求的类型.因为System.Web.Routing中提供了HttpMethodConstraint类, 这个类实现了IRouteConstraint 接口. 我们可以通过为RouteValueDictionary字典对象添加键为"httpMethod", 值为一个HttpMethodConstraint对象来为路由规则添加HTTP 谓词的限制, 比如限制一条路由规则只能处理GET请求: httpMethod = new HttpMethodConstraint( "GET", "POST" )

View Code
             routes.MapRoute(                  "Default", // Route name                  "{controller}/{action}/{id}", // URL with parameters                  new { controller = "Home", action = "Index", id = "" }, // Parameter defaults                  new { controller = @"\d{4}" , httpMethod = new HttpMethodConstraint( "GET", "POST" ) }                  );

我们注册这样的一条路由

自定义带过滤的路由
      routes.MapRoute(                "test", // Route name                "{controller}-{action}-{id}", // URL with parameters                new { controller = "Home", action = "Index" }, // Parameter defaults                new { controller = @"^\w ", action = @"^\w ", id = @"^\d " }            );

编译且运行,当我们请求/home-index-11可以请求到,而我们/home-index-1x这样的是不能匹配的,

那这样的规则的又有什么用处呢?在这里可以对请求进行过滤,比如我们的id只能是数字类型,防止一些非法检测

路由组件的调试

假设我们写了N条路由,当我们发送请求的时候,并没有被我们想要的规则所捕获解析,so..我们需要调试。

在我们的项目添加RouteDebug.dll的引用,并在Global.asax文件中的Application_Start方法添加以下代码

启用路由调试
        protected void Application_Start()        {            AreaRegistration.RegisterAllAreas();            RegisterRoutes(RouteTable.Routes);            //启动路由表调试            RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);        }

编译后,我们启动程序,会发现有一个Route Tester页面,关于RouteDebug匹配的页面信息,请大家查询RouteDebug的手册.

Route Tester中的Route Data请求就是当前请求的路由信息

 我们请求/home/index,从图中可以看到被第4条路由捕获到.

  那这样的路由有什么作用呢?我想大部分做SEO的朋友都有经验,二级页面和三级页面,爬虫抓取的频率显然是不一样的,这样我们可以将三级甚至更深层的页面构造成二级页面~这个也是SEO的技巧之一

注意:我们在写路由规则的时候,因为路由规则有前后顺序(指注册的先后顺序),也许写的路由规则被它前面的规则给捕获到,进行处理。那后面注册的路由就无效

 

2、Controller学习

  在ASP.NET MVC中, 一个Controller可以包含多个Action. 每一个Action都是一个方法, 返回一个ActionResult实例.

   ActionResult类包括ExecuteResult方法, 当ActionResult对象返回后会执行此方法.

  Controller 处理流程:

  1. 页面处理流程 发送请求 –> UrlRoutingModule捕获请求 –> MvcRouteHandler.GetHttpHandler() –> MvcHandler.ProcessRequest

  2.MvcHandler.ProcessRequest() 处理流程:使用工厂方法获取具体的Controller –> Controller.Execute() –> 释放Controller对象

  3.Controller.Execute() 处理流程: 获取Action –> 调用Action方法获取返回的ActionResult –> 调用ActionResult.ExecuteResult() 方法

  4.ActionResult.ExecuteResult() 处理流程: 获取IView对象-> 根据IView对象中的页面路径获取Page类-> 调用IView.RenderView() 方法(内部调用Page.RenderView方法)

  Controller对象的职责是传递数据,获取View对象(实现了IView接口的类),通知View对象显示.

  View对象的作用是显示.虽然显示的方法RenderView()是由Controller调用的,但是Controller仅仅是一个"指挥官"的作用, 具体的显示逻辑仍然在View对象中.

     注意IView接口与具体的ViewPage之间的联系.在Controller和View之间还存在着IView对象.对于ASP.NET程序提供了 WebFormView对象实现了IView接口.WebFormView负责根据虚拟目录获取具体的Page类,然后调用 Page.RenderView()

 

Controller中的ActionResult

在Controller中,每一个Aciton返回都是ActionResult,我们通过查看ActionResult的定义

ActionResult
    // Summary:    //     Encapsulates the result of an action method and is used to perform a framework-level    //     operation on behalf of the action method.    public abstract class ActionResult    {        // Summary:        //     Initializes a new instance of the System.Web.Mvc.ActionResult class.        protected ActionResult();        // Summary:        //     Enables processing of the result of an action method by a custom type that        //     inherits from the System.Web.Mvc.ActionResult class.        //        // Parameters:        //   context:        //     The context in which the result is executed. The context information includes        //     the controller, HTTP content, request context, and route data.        public abstract void ExecuteResult(ControllerContext context);    }

关于ActionResult的派生类,大家可以参考:http://blog.csdn.net/steven_husm/article/details/4641281

 

3、Filter的学习

mvc项目中,action在执行前或执行后想做一些特殊的操作,比如身份校验、行为截取等,asp.net mvc提供了以下几种默认的Filter

ASP.NET MVC 框架支持以下几种筛选器:

1、授权筛选器– 实现了 IAuthorizationFilter 接口

  这一类的筛选器用来实现用户验证和对Action的访问授权。比如Authorize 就属于Authorization 筛选器。

2、Action 筛选器– 实现了 IActionFilter 接口

  它可以包含一些Action执行前或者执行后的逻辑,比如有一些筛选器专门用来修改Action返回的数据。

3、Result 筛选器– 实现了 IResultFilter 接口

  它可以包含一些view result生成前或者生成后的逻辑,比如有一些筛选器专门用来修改视图向浏览器展现前的结果。

4、异常筛选器– 实现了IExceptionFilter 接口

  它用以用来处理Action或者Result的错误,也可以记录错误。

     筛选器的默认执行顺序也和上面的列出的序号相同,比如Authorization 筛选器会先于Action 筛选器执行,而Exception 筛选器总会在最后执行。当然你也可以根据需要通过Order属性设定筛选器执行的顺序。

下面通过一个实际的例子来说明应用,新建一个mvc3项目,在项目中新加一个Common文件夹,并新加一个类LogUserOperationAttribute.cs

LogUserOperationAttribute
    public class LogUserOperationAttribute : ActionFilterAttribute    {        public override void OnResultExecuted(ResultExecutedContext filterContext)        {            //todo写日志代码,这里注意并发性            File.AppendAllText(@"C:\log.txt", string.Format("{0}日志", DateTime.Now));            base.OnResultExecuted(filterContext);        }    }

新加一个HomeControllers,并在HomeControllers中新加一个Action--Index以及视图文件

HomeController
    public class HomeController : Controller    {        //        // GET: /Home/        [LogUserOperation]        public ActionResult Index()        {            return View();        }    }

然后保存代码,F5运行,当页面显示出来以后,在C盘已经有log.txt文件.

abstract class ActionFilterAttribute这四个方法分别代表,Action执行时,Action执行后,Result返回时,Result返回后。(它们的执行顺序跟下图一致)

     当然,我们也可以在ASP.NET MVC 3.0中增加Global Action Filter,这个就把此类filter变成全局的filter,所有Controller的action都会通过个filter的规则来执行,它跟我们在Controller或某个action所标识的属性有很大的区别,就是全局跟部分的区别。对于Global Action Filter 有着很多的应用,比如系统的权限、系统异常的处理

Gloable Filter实际应用--系统异常处理体系

我们程序运行过程中会有各种不可预料的情况,执行某个Action会发生异常,那我们异常信息需要记录下来,我们可以像上面的例子一样,在Action或Controller上打上标记,但是那么多action和Controller都去打标记,确实是很痛苦的事情,而asp.net mvc3有一个全局的Filter,我们只需要将我们自定义的Filter注册成全局的Filter

在Common文件夹中,新建一个类CustomHandleErrorAttribute.cs

CustomHandleErrorAttribute
    public class CustomHandleErrorAttribute : IExceptionFilter     {        public void OnException(ExceptionContext filterContext)        {            File.AppendAllText(@"C:\error.txt", string.Format("{0}错误{1}", DateTime.Now, filterContext.Exception.Message));        }    }

在Global.asax文件中,RegisterGlobalFilters方法写注册代码

注册全局Filters
     public static void RegisterGlobalFilters(GlobalFilterCollection filters)        {            filters.Add(new CustomHandleErrorAttribute());//系统的逻辑错误通过这个filters来处理            filters.Add(new HandleErrorAttribute());        }

 在HomeController中新加一个Action--->Error

HomeController
    public class HomeController : Controller    {        //        // GET: /Home/        [LogUserOperation]        public ActionResult Index()        {            return View();        }        public ActionResult Error()        {            try            {                System.IO.File.Open("C:\\111111.exe", System.IO.FileMode.Open);            }            catch (Exception ex)            {                throw ex;            }            return View();        }    }

编译后运行项目~我们请求/Home/Error这个action,,程序出现异常,我们切换到C盘,发现C盘已经有error.txt文件
注册到全局的Filters所有的ActionResult执行前后都会调用我们的CustomHandleErrorAttribute的重写的方法。

GlobalFilters、ControllerFilters、ActionFilters的执行顺序问题

GlobalFilters-->ControllerFilters-->ActionFilters《这个是有执行的前置条件的》

   当然这是在CustomHandleErrorAttribute类的定义上打上标记[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]的前提下。不然 如果Action打上了标签跟Controller的相同则它只会执行Action上的Filter

 

作者:wolfram  原文链接

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 早教课上宝宝坐不住怎么办? 孩子在幼儿园上课坐不住怎么办 小孩不会写拼音a怎么办 小朋友上课注意力不集中怎么办 一年级孩子上课爱说话怎么办 一年级小孩不听老师话怎么办 大班幼儿规则意识差怎么办 幼儿大班《打雷了怎么办》的教案 小孩上课不听讲到处乱跑怎么办 小孩子经常咬人好动怎么办 6个月宝宝好动怎么办 新生调皮被幼儿园退学怎么办 孩子在幼儿园太调皮怎么办 幼儿上课注意力不集中怎么办 幼儿上课一半要离开怎么办 八个月宝宝消化不良拉肚子怎么办 8个月的宝宝拉肚子怎么办 孕8个月拉稀怎么办 孩子调皮好动爱说话怎么办 宝宝8个月不会爬怎么办 怀孕8个月不想要了怎么办 8个月宝宝发烧怎么办 八个月的小孩发烧怎么办 孩子8个月发烧38怎么办 8个宝宝发烧38度怎么办 怀孕八个月不想要怎么办 怀孕八个月不想要了怎么办 八个月宝宝拉肚子拉水怎么办 八个月的宝宝拉肚子怎么办 八个月发烧38度怎么办 孩子特别调皮好动该怎么办 孩子有好动症该怎么办 在幼儿园好动的孩子该怎么办 18个月宝宝上火怎么办 打孩子越打上瘾怎么办 八个月不想要了怎么办 胎儿心脏畸形肺动脉瓣闭锁怎么办 小孩爱动怎么办补什么 初中孩子下午上课总犯困怎么办 孩子上课精神不集中怎么办 孩子玩兴奋了就打人怎么办