在MVC的项目中有一个Global.asax.cs 文件,里面有一个 Application_Start 方法,代码如下:
public class MvcApplication : System.Web.HttpApplication { /// <summary> ///不是每次请求都调用 ///在Web应用程序的生命周期里就执行一次 ///在应用程序第一次启动和应用程序域创建时被调用 ///适合处理应用程序范围的初始化代码 /// </summary> protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes);//注册路由 BundleConfig.RegisterBundles(BundleTable.Bundles); } }
这个地方就是开启路由的地方,它把url包装成Route对象,然后把我们注册的路由规则用name---route键值对的方式存入RouteCollection中(注册的路由写在App_Start 文件加下面的 RouteConfig 里面),当请求来了后,会在RouteCollection进行路由解析,就会根据自定义的路由规则从上到下进行匹配
路由解析:
1.如果没有匹配上我们定义的路由,那么就走原始流程,就等于MVC中路由完全没有生效
2.如果请求能够找到物理文件,那么就不再匹配路由(支持WebForm的原因)
3.匹配路由是从上到下进行匹配的,如果第一个匹配上了,那么就不会继续往下匹配了,如果匹配不上,那么就走原始流程
WebForm请求:
WebForm请求的是一个具体的页面,当用户请求具体的aspx页面时,服务器会对该页面中的内容一行一行的解析(碰到服务器脚本语言还会执行),最后形成响应流重新写回到浏览器,再由浏览器对该响应流进行解析(依照W3C标准),最终将用户请求的页面呈现出来
注册路由的几种方式如下:
1.在RouteConfig 里面注册路由
参数说明:
name: 路由名称
url: url参数
defaults: 参数默认值
constraints: 参数约束(常用的是正则表达式)
/* 默认路由规则 这个表示只匹配所有控制器下面的动作,如果不指定控制器和动作,那么默认访问Home控制器下的Index动作,如果指定了,那么就访问指定的控制器下的动作 */ routes.MapRoute( name: "Default1", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); /* 指定控制器(就是把控制器写死) 这个表示只匹配Home控制器下面的动作,如果不指定动作,那么默认访问Index动作,如果指定了,那么就访问指定的动作 */ routes.MapRoute( name: "Default2", url: "Home/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); /* 指定控制器和动作(就是把控制器和动作写死) 这个表示只匹配Home控制器下面Index动作 */ routes.MapRoute( name: "Default3", url: "Home/Index/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); /* 给路由定义约束(constraints) 这个表示只能匹配Home和Index控制器下面的Index方法 */ routes.MapRoute( name: "Default4", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, constraints: new { controller = "Home|Index", action = "Index" } ); /* 给路由定义约束(constraints) 这个表示只能匹配Home和Index控制器下面的Index方法,并且一定要带一个参数 id,不管动作是否需要参数,不带访问不到啊(例如:localhost:8955/Index/Index_100) 这样写的好处是GET请求的时,让别人不知到你这参数是干什么的,是什么字段 注意: 这个地方可以随意拼接例如:{controller}_{id}/{action} {controller}/{action}/_{id} */ routes.MapRoute( name: "Default4", url: "{controller}/{action}/_{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, constraints: new { controller = "Home|Index", action = "Index" } ); /* 给路由定义约束(constraints)----正则表达式 这个表示 1.只能匹配Home和Index控制器下面的Index方法,并且一定要带一个参数 id, 2.并且id的值是五个数字组成 (例如:localhost:8955/Home/Index_10000) 3.此路有之匹配GET请求 */ routes.MapRoute( name: "Default4", url: "{controller}/{action}_{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, constraints: new { controller = "Home|Index", action = "Index",id=@"d{5}",httpMethod = new HttpMethodConstraint("GET") } );
2.使用特性注册路由(RouteAttribute)
使用:
首先我们在RouteConfig 里面启动特性路由,将特性 RouteAttribute 标记到控制器或控制器操作上。
public static void RegisterRoutes(RouteCollection routes) { /* IgnoreRoute为RouteCollection 的扩展方法,作用是忽略指定样式的路由。 上面routes.IgnoreRoute("{resource}.axd/{*pathInfo}");中的{resource}代表一个路由参数, 上面routes.IgnoreRoute("{resource}.axd/{*pathInfo}");中的{resource}代表一个路由参数, { resource}.axd代表以.axd结尾的字符串;{*pathInfo}也是一个路由参数,*代表匹配任何字符串, 那么以pathInfo结尾的串都会匹配到。这条语句完整含义是:以axd结尾的任何字符串,不论斜杠后是何种字符串都不执行路由行为。 */ routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapMvcAttributeRoutes();//启动路由 }
使用特性的三个属性或构造函数:
public RouteAttribute(string template):template是路由匹配模式
Name:获取或设置路由名称
Order:获取或设置路由应用顺序
Template:获取路由匹配模式
public class HomeController : Controller { /// <summary> /// url:localhost:8955/Home/Index /// </summary> [RouteAttribute("Home/Index")] public ActionResult Index() { return View(); } /// <summary> /// url:localhost:8955/Home-Index /// </summary> [RouteAttribute("Home-Index")] public ActionResult Index() { return View(); } /// <summary> /// url:localhost:8955/Home/aaa /// </summary> [RouteAttribute("Home/aaa")] public ActionResult Index() { return View(); } /// <summary> /// url:localhost:8955/Home/10-10 /// 注意: /// 如果动作里面有2个参数,此参数是无任何类型的 a b(public ActionResult Index(int a, int b)),那么参数a为10,参数b为10 /// 不管动作是否有参数,都需要传递值进来(不能 localhost:8955/Home) /// </summary> [RouteAttribute("Home/{a}-{b}")] public ActionResult Index(int a, int b) { return View(); } /// <summary> /// url:localhost:8955/Home/10-10 /// 注意: /// 不管动作是否有参数,都需要传递值进来(不能 localhost:8955/Home) /// a 无任何类型 b 只接受int类型的值(如果要接受时间类型:{b:datetime}) /// </summary> [RouteAttribute("Home/{a}-{b:int}")] public ActionResult Index() { return View(); } [RouteAttribute("Home/Main")] public ActionResult Main() { return View(); } }
当然,因为在同一个控制器中,所有动作的控制器的名称都是一样的,所以我们可以在控制器上面使用定义公共路由
当然需要更加了解可以访问:https://www.cnblogs.com/ITusk/p/7677001.html
namespace WebApplication1.Controllers { [RoutePrefixAttribute("Home/{id}")] public class HomeController : Controller { /// <summary> /// url:localhost:8955/Home/15/Index /// </summary> [RouteAttribute("Index")] public ActionResult Index() { return View(); } } }
我们可以使用 ?
将一个路由参数标记为 可选参数(optional parameter),如果一个路由参数被标记为可选的,则必须为其设置默认值
[Route("api/product/{id:int?}")] public IHttpActionResult GetProduct(int id =1){ }
可以同时使用多个约束条件,每个条件之间通过 :
进行分割,例如
[Route("api/product/{id:int:min(1)}")] public IHttpActionResult GetProduct(int id){}
课外补充:
URL与搜索引擎优化
1)URL越短越好
2)用破折号而不是下划线
3)使用小写字母。根据HTTP规范,URL区分大小写,一般的搜索引擎遵循HTTP规范
Glimpse:
使用Glimpse观察路由
安装:打开VS->工具->NuGet程序包管理器->搜索Glimpse.MVC5,然后回车,执行安装
使用:
1.运行web应用,输入地址格式为:网站根目录/glimpse.axd,例如 localhost:8955/glimpse.axd
2.点击页面中的Turn Glimpse On 按钮
3.运行你要测试页面地址