《精通ASP.NET MVC4》学习笔记
第7-11章 SportStore项目实践
(见个人项目CY.SportsStoreMVC)
第12章 MVC项目综述
理解约定优于配置:不用明确的配置应用程序中的某种关联,只要遵守某种约定,一切都会正常工作。(可以修改这种约定,不过会带来大量的修改工作。个人理解:将关联写入配置文件,应用程序需要使用大量的反射机制获取配置中的关联,这反而会降低应用程序的性能)
约定包括命名约定、控制器和视图关联约定、布局约定等。
第13章 URL路由(处理输入URL)
路由系统的两个功能:
1、匹配请求(输入)URL,找到对应的控制器和动作方法;
2、生成响应(输出)URL,方便下一次请求。
名词理解:
URL中片段值-->域名之后用‘/’分隔的内容;
片段变量-->路由中URL模式中以占位符的形式定义的部分;
静态片段—>URL模式中非占位符形式的部分(URL中片段内容必须与其相同才能匹配)
注:路由系统和MVC框架是没有任何关联的(路由是asp.net平台下的一种技术),只是单纯的匹配请求URL中的片段(将路由中定义的模式与请求URL匹配,若匹配成功,将URL中片段的值赋给模式中定义的片段变量),匹配出来的片段变量值会沿着请求管道传给MVC应用程序(路由系统并不关心MVC系统中是否存在相应的Controller和action)
路由匹配规则:按片段顺序进行匹配,配少不配多,少的部分由默认值代替(解释:URL中的片段数不能多于路由模式中定义的片段变量数,一个片段值匹配一个片段变量,若URL中未提供路由模式中定义的某一片段变量的值,使用路由中定义的默认值代替)
路由匹配顺序:一般按照其定义顺序逐个匹配,原则是具体的放在前面,保证先被匹配到。
使用路由中的默认值替换URL中指定的controller或action:
route.MapRoute("shopSchema", "shop/{action}", new {controller="home"});
该路由会将url中shop/index请求转换到home/index下
通过请求URL给MVC动作方法传值的几种方式:
1、获取URL中查询变量的值(?后面的值) ?id=111 –> Request["id"]
2、将URL中的某一片断值(片段用‘/’分隔)传给路由模式中定义的片段变量(定义的该片段变量必须是自定义的,非controller、action等默认的),然后再用动作方法参数匹配该片段变量获取该值(匹配过程由模型绑定器完成,方法参数名和片段变量名要一致(不区分大小写)才能匹配成功)(在动作方法中使用RouteData.Values属性同样可以获取到路由中片段变量的值)
使用{*catchall}片段变量定义可变长路由:
//该路由模式可匹配任意片段数的URL,URL中前三个片段之后的所有片段都将赋给catchall
routes.MapRoute(“MyRoute”,”{controller}/{action}/{id}/{*catchall}”,new {controller=”Home”,action=”Index”,id=”UrlParameter.Optional”});
路由中指定优先查找的控制器类:
在一个字符串数组中指定要优先处理的控制器类所在命名空间,指示mvc框架优先查找指定的命名空间,若指定的命名空间中没有找到相应的控制器类,则回到mvc框架的正常默认行为。
注:
1、字符串数组中指定的多个命名空间不具有优先顺序,若想指定多个优先查找的命名空间,则必须定义多条不同的路由;
2、使用myRoute.DataTokens[“UseNamespaceFallback”]=false通知mvc框架只查找字符串数组中指定的命名空间。
Route myRoute = routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional }, namespaces: new[] { "CY.SportsStoreMVC.WebUI.Controllers" } ); myRoute.DataTokens["UseNamespaceFallback"] = false;
URL请求磁盘文件:
默认情况下,路由系统在评估应用程序路由之前,会先检查是否有磁盘文件和url匹配,若存在匹配的磁盘文件,则直接请求该磁盘文件。
若想要路由系统评估磁盘文件,又想要能够直接请求某一类型磁盘文件,可以使用如下方式:
//通知路由系统评估磁盘文件 routes.RouteExsitingFiles = true; //通知路由系统若匹配到这一URL模式,则不再评估后续路由,直接请求该URL routes.IgnoreRoute("Content/{filename}.html");
第14章 高级路由特性(使用路由系统生成输出URL)
使用路由系统生成输出URL的好处是:当路由方案发生变化时,这种变化会自动的反映到输出URL,相对于通过硬编码的方式写入URL,应用程序具有更好的可维护性。
路由系统生成输出URL的原理:
路由系统会根据当前查找到的片段变量的值来按顺序匹配路由表中定义的路由,匹配成功的三个条件如下:
一、为当前评估的路由找到各片段变量的值,这些值的来源及其查找顺序如下:
1、ActionLink或Action方法中routeValues参数明确提供的值,routeValues参数可以是匿名类型,也可以是RouteValueDictionary
2、当前请求上下文的RouteData(意指当前请求URL中为其匹配的路由URL模式中设置的片段值)
3、当前要评估的路由中defaults默认值
二、对于未出现在待评估路由的url模式中但设置了默认值的片段变量,mvc应用程序最好不要提供该值,否则提供的值必须与路由中定义的默认值匹配才可以;
三、为当前评估的路由找到各片段变量的值必须满足路由中定义的约束条件。
注:URL模式中片段变量是按顺序被赋值的,当某一片段变量被routeValues参数中提供的值赋值成功后,其后续片段变量便不能被其它数据源赋值(如当前请求的RouteData),所以最好在routeValues参数中明确的给URL模式中的每一个片段变量提供值
(第14章 以上知识点总结于书本和网上,未经实例验证)
定制路由
1、自定义路由类必须继承自RouteBase基类
public class LegacyRoute:RouteBase
2、必须重写方法GetRouteData和VirtualPathData
//路由系统将调用GetRouteData方法用于匹配入站URL public override RouteData GetRouteData(HttpContextBase httpContext)
//路由系统调用此方法使用获取到的路由数据(参数RouteValueDictionary values)生成出站URL public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
3、注册添加自定义路由
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); //自定义路由: routes.Add(new LegacyRoute("~/articles/windows_3.1_overview.html", "~/old/.net_1.1_Class"));
自定义路由处理程序
路由处理程序是连接路由系统和MVC框架的桥梁,自定义路由处理程序必须实现IRouteHandler接口,负责完成控制器查找、动作方法调用、视图渲染等功能。(较复杂,暂不深究)
定义与使用MVC应用程序中的区域(Areas)
1、添加区域:右键solution explorert添加区域,区域目录结构Areas/{AreaName},{AreaName}文件夹下面controller、Models、Views等
2、添加区域之后,{AreaName}文件夹下有一个AdminAreaRegistration.cs文件,AdminAreaRegistration类派生于AreaRegistration,用于注册当前区域专属路由:
public class AdminAreaRegistration : AreaRegistration { public override string AreaName { get { return "Admin"; } } public override void RegisterArea(AreaRegistrationContext context) { //如果给路由赋名,必须确保该名称在整个应用程序内而非该区域内是唯一的 //MapRoute方法会自动将在此处注册的路由查找范围限制到包含该区域控制所在命名空间中, //这意味着在该区域中添加的控制器,必须在其默认的命名空间中定义 context.MapRoute( "Admin_default", "Admin/{controller}/{action}/{id}", new { action = "Index", id = UrlParameter.Optional } ); } }
3、在MVC应用程序Global.asax文件中会自动添加一行代码注册区域路由:
protected void Application_Start() { //注册区域路由: //系统将使用此方法遍历所有派生于AreaRegistration的类,并调用这些类的RegisterArea方法 //注:由于路由是按顺序评估的,RegisterAllAreas方法的调用必须在RegisterRoutes方法的调用之前,否则可能进行不正确的匹配 AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); }
4、不同区域之间的链接跳转:
在使用匿名类型定义的RouteValueCollection中,通过给片段变量area赋值,通知应用程序切换不同的区域,赋空字符串值时将切换到项目主区。
@Html.ActionLink("click me", "GetLegacyURL", "Legacy", new { area = "", legacyURL = "~/articles/windows_3.1_overview.html" }, null)
第15章 控制器与动作
控制器
标准控制器派生于Controller类,Controller实现了IController接口(同时还实现了很多其它的接口),实现了IController中的唯一Execute方法,在Execute方法中负责调用自定义的动作方法。
Controller类为其派生类提供了一组便利属性(convenience property),使用点语法通过ControllerContext实例获取。
便利属性中提供的常用上下文对象(获取请求相关信息):
string strGetParam = this.ControllerContext.HttpContext.Request.QueryString["getParam"]; string strPostParam = this.ControllerContext.HttpContext.Request.Form["postParam"]; HttpCookie cookies = this.ControllerContext.HttpContext.Request.Cookies["cookie"]; RouteBase route = this.ControllerContext.RouteData.Route; RouteData routeData = route.GetRouteData(this.ControllerContext.HttpContext); RouteData routeData2 = this.ControllerContext.RouteData; string strController = routeData2.Values["controller"].ToString(); string strAction = routeData2.Values["action"].ToString(); //未完待续...
控制器接受输入数据(如查询字符串、表单值,以及路由数据)的三种方法:
1、使用上述便利属性中的上下文对象进行提取;
2、使用动作方法参数获取数据;
使用动作方法需要注意的几点:
1、MVC框架使用内建的值提供器(value provider)和模型绑定器(model binder)组件获取参数实例填充参数,值提供器负责从相关上下文对象(如request.QueryString、Request.Form、Request.Files)抓取数据,模型绑定器负责将这些数据映射成参数数据类型并填充参数;
2、动作方法参数未匹配到对应数据的情况下:
对于引用类型,会默认提供null值;
对于值类型,将会抛出异常。解决办法:使用可空类型定义参数(如int? i//在未提供i值的情况下,会使用null值代替);使用可选参数定义参数默认值(如int i=1),可选参数可用于字面类型(字面类型指不需要使用new关键字创建类型,包括string)
3、如果提供的参数值无法转换成参数类型,系统将使用该类型的默认值,并添加一个模型验证错误。
3、使用模型绑定(后续章节阐述)
动作
动作方法处理接受的输入请求后产生输出的原理:
动作方法处理完输入请求后返回一个ActionResult类型的对象给MVC框架,MVC框架会调用ActionResult对象中的ExecuteResult方法处理输出响应。ActionResult实际上是一种命令模式(命令模式是一种设计模式,指为执行某一操作的命令(如调用某一方法)封装一个对象,该对象包含一些信息,如目标方法,目标方法属主(方法所属对象)以及调用方法所需参数)。
将数据从动作方法传递给视图的几种方式:
1、使用视图模型对象;
若一个视图没有指定模型类型,那么视图为弱类型视图,视图将把传递过来的模型对象视为object处理,使用前需要先转换成相应类型。指定视图模型类型:@model DateTime,此时为强类型视 图。
2、使用ViewBag动态对象;
注:ViewBag无法跨请求使用。
3、使用TempData对象(非动态对象,使用键/值对表示);
注:TempData可以跨请求使用,在其数据被读取后会被标记为删除,在请求处理完成之后会被马上删除。
使用TempData对象的peek方法读取数据,而不标记删除;使用keep方法保留一个将被删除的数据(只保留一次)。