webForm页面运行起来url一般是这样的:localhost:****/index.aspx,这个过程就是当你运行页面的时候,vs开发工具自带的微型服务器会打开你存在硬盘上的这个文件然后显示在浏览器上,所以url是后半部分是页面的名字(index.aspx),但是在mvc中却是这样的:localhost:****/index,因为mvc中有一整套路由机制来控制浏览器的请求。

看看Global.asax文件里路由的定义:

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute(
"Default", // 路由名称
"{controller}/{action}/{id}", // 带有参数的 URL
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值
);
}

注释掉这个默认的路由,自己重新定义一个路由:

根据vs的只能提示可以看出参数一个是路由名称,一个是路由的模式,定义为这样:

routes.MapRoute("MyRoute", "{controller}/{action}");

有了路由了就可以去创建控制器了,新建一个HomeController:

public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}

再去创建一个对应的View:

@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<div>
HomeController下的Index Action响应的同名视图Index
</div>
</body>
</html>

直接运行程序发现报404错误,找不到页面。查看下路由就知道了问题:这个路由指定的是url模式是{controller}/{action}的方式,而浏览器里的url却是localhost:****,既没有写Controller,也没有写Action,显然不符合路由的定义,自然得报404错了。把Url补充完整就可以找到页面了:localhost:****/home/index,当然如果在url后面少一级或者多加一级都会报404错:localhost:****/home、localhost:****/home/index/1,可见Url必须严格根据路由的定义来。
当然,也可以在路由定义的时候就给默认值:

routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" });

这样运行程序就不报错了:localhost:****,根据路由给的默认值就相当于:localhost:****/home/index

再看这两条路由的定义:

routes.MapRoute("", "Customers/{controller}/{action}");
routes.MapRoute("", "X{controller}/{action}");

第一条路由对应的Url是这样的:localhost:****/Customers/Home/Index
第二条是:localhost:****/XHome/Index
区别:第一条是静态的路由,第一级目录必须是路由里指定了的Customers,而第二条路由则是动态可变的,第一级只要以X开头都可以和本路由匹配上

路由的顺序:
如果同时定义了这么两条路由:

routes.MapRoute("MyRoute", "{controller}/{action}");
routes.MapRoute("", "X{controller}/{action}");

现在浏览器有这么条Url请求过来了:localhost:****/XHome/Index 看到XHome好像得使第二条路由了,但是不是。这条Url同时符合两条路由就优先使用前面的路由。根据第一条路由,这条Url过去就是找XHome这个控制器Controller里的Index Action

混合的静态路由,带默认值:

routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); 

这条名为ShopSchema的路由没有定义Controller,而是给了一个默认值Home,但是如果直接请求localhost:****/home/index 虽然有HomeController,但是还是会报404,因为路由已经限制了Controller部分必须是Shop,所以url得是这样:localhost:****/shop/index,虽然没有ShopController,但是同样会导向到HomeController下。
注:为了演示路由效果,防止前面定义的路由影响到Url请求的控制器,所以得先把之前的所有路由都注释了再运行查看效果。

routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" });

Url:localhost:1042/shop/OldAction 找的同样是HomeController下的Index这个Action

定义额外的参数:
路由当然不光可以定义controller和action,同时也可以定义之后的参数,比如:

routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "" });

在控制器下可以这么拿到传进来的id参数:ViewBag.CustomVariable = RouteData.Values["id"];
视图View中这么调用:@ViewBag.CustomVariable

{controller}/{action}/{id} 对应的url是这样的:localhost:****/home/index/10010  视图中输出:10010

当然,因为路由给了默认值,所有一下url都可以:
localhost:****
localhost:****/home
localhost:****/home/index  输出的都是:10086

可选参数:

routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });

Optional这个在EF配置实体之间的一对一、一对多等关系里演示过,表示可选的意思,这里的路由也是一样,表示id部分就是可选的:
localhost:**** =>  controller = Home  action = Index
localhost:****/Customer  =>  controller = Home  action = Index
localhost:****/Customer/List  =>  controller = Home  action = Index
localhost:****/Customer/List/All  =>  controller = Home  action = Index  id = All

可变长度的路由:

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });

localhost:**** =>  controller = Home  action = Index
localhost:****/Customer  =>  controller = Home  action = Index
localhost:****/Customer/List  =>  controller = Home  action = Index
localhost:****/Customer/List/All  =>  controller = Home  action = Index  id = All
localhost:****/Customer/List/All/Delete  =>  controller = Home  action = Index  id = All  catchall = Delete
localhost:****/Customer/List/All/Delete/Perm  =>  controller = Home  action = Index  id = All  catchall = Delete/Perm

指定命名空间:

routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" });

这是一个极普通的路由,项目运行起来,默认找的是HomeController下的Index这个Action,但是现在如果项目下同个命名空间有两个HomeController怎么办,那自然要报错的:


可以指定命名空间:

routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }, new[] { "RouteDemo4Blog.Controllers" });

正则表达式路由:

routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }, new { controller = "^H.*" });

可适配所有以字母H开头的Controller 再来一个:

routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }, new { controller = "^H.*", action = "^Index$|^About$" });

元字符^和$分别匹配字符串的开始和结束 | 表示或,所有这个路由匹配名为Index或者About的Action

指定url请求方式:

routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }, new { controller = "^H.*", action = "Index|About", httpMethod = new HttpMethodConstraint("GET") });

只响应GET请求(默认)

传递额外的值:

@Html.ActionLink("About this application", "About", new { id = "MyID" }) 

生成的HTML就是:

<a href="/Home/About/MyID">About this application</a>

点击页面上这个a标签自然区找的就是对应的路由了。

@Html.ActionLink("Click me", "List", "Catalog", new {page=}, null) 

生成的HTML:

<a href="/Catalog/List/Purple/789">Click me</a>

对应的路由自然就是这样的:

routes.MapRoute("MyRoute", "{controller}/{action}/{color}/{page}"); 

指定css:

@Html.ActionLink("About this application", "Index", "Home", null,  new {id = "myAnchorID", @class = "myCSSClass"}) 
<a class="myCSSClass" href="/" id="myAnchorID">About this application</a> 

生成完整的url:
之前生成的都是相对路径的Url,现在看看绝对路径的:

@Html.ActionLink("About this application", "Index", "Home",
"https", "myserver.mydomain.com", " myFragmentName",
new { id = "MyId"},
new { id = "myAnchorID", @class = "myCSSClass"})

生成的HTML:

<a class="myCSSClass" href="https://myserver.mydomain.com/Home/Index/MyId#myFragmentName" id="myAnchorID">About this application</a>

生成Url:
之前的@Html.ActionLink方法生成的都是a标签,看看如何生成url:

@Url.Action("Index", "Home", new { id = "MyId" }) 
/Home/Index/MyId

Areas

Areas官方的解释是为了划分功能使用的,比如区分:管理员、订单、客户等功能,适合大项目使用,同时方便程序员之间协同开发。来一个试试:右键解决方案 - 添加 - 区域 - Admin - 确定

可以看出每个区域Areas里都是个mini的MVC项目,Controller、Models、Views一个都不缺,还多了一个AdminAreaRegistration类,看看其中的代码:

public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
} public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}

可以看出其中已经有一个默认的路由了,跟普通的MVC项目是一样的,只不过前面多了一个Admin。向这个Areas里添加一个Controller试试:右键Controllers目录 - 添加 - 控制器 - HomeController 同时添加对应的视图Index:

@{
ViewBag.Title = "Index";
}
<h2>
Admin Area Index</h2>

运行下程序,url定位到:localhost:1042/admin/home/index就能显示这个视图了。但是如果直接请求localhost:1042会报错:

很明显是因为默认的路由和Areas下的路由冲突了,这个之前演示过。解决方法就是加上命名空间:'

routes.MapRoute(
"Default", // 路由名称
"{controller}/{action}/{id}", // 带有参数的 URL
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // 参数默认值
new[] { "RouteDemo4Blog.Controllers" }
);

当然也可以从一个Areas跳转到另一个Areas:

@Html.ActionLink("跳转到别的Areas", "Index", new { area = "Support" }) 

生成的HTML:

<a href="/Support/Home">跳转到别的Areas</a> 

跳转到顶级Controller:

@Html.ActionLink("Click me to go to another area", "Index", new { area = "" })

本文源码

系列文章导航

ASP.NET MVC Routing、Areas、URLs的更多相关文章

  1. 七天学会ASP.NET MVC (六)——线程问题、异常处理、自定义URL

    本节又带了一些常用的,却很难理解的问题,本节从文件上传功能的实现引出了线程使用,介绍了线程饥饿的解决方法,异常处理方法,了解RouteTable自定义路径 . 系列文章 七天学会ASP.NET MVC ...

  2. Asp.Net MVC<一> : 三层架构、MVC

    MVC.MVP.MVVM.Angular.js.Knockout.js.Backbone.js.React.js.Ember.js.Avalon.js.Vue.js 概念摘录 认清Android框架 ...

  3. asp.net mvc移除X-AspNet-Version、X-AspNetMvc-Version、Server

    asp.net mvc程序部署到IIS,,返回的HTTP头中包含Server, X-Powered-By, 和 X-AspNet-Version.X-AspNet-Version信息. 这些信息有时给 ...

  4. ASP.NET MVC Routing学习笔记(一)

    Routing在ASP.NET MVC中是非常核心的技术,属于ASP.NET MVC几大核心技术之一,在使用Routing之前,得先引入System.Web.Routing,但其实不用这么麻烦,因为在 ...

  5. 5. ASP.NET MVC 中的Areas【区域】是什么

    [PS返回上一篇:-->4.ASP.NET MVC 5.0 视图之模型绑定] 从ASP.NET MVC 2.0开始,微软就提供了一个新特性:Areas[区域].Areas仅仅是用来将大型程序拆分 ...

  6. Asp.Net MVC<六>:Controller、Action 待续

    控制器 抽象类Controller Visual Studio的向导创建的Controller类型继承自抽象类Controller. 它是ControllerBase的子类. 实现了IControll ...

  7. Asp.Net MVC之 自动装配、动态路径(链接)等

    一.Model层 using System; using System.Collections.Generic; using System.Linq; using System.Web; namesp ...

  8. 一张图说清Asp.NET MVC中的 RenderPage、RenderBody、RenderSection

  9. Asp.Net MVC:return View()、return View("Login")、return Login()、return RedirectToAction("Login") 的区别

    在做登录页面的时候发现的一些情况: ------------------------------------------------------------------------- public A ...

随机推荐

  1. 复化梯形求积分——用Python进行数值计算

    用程序来求积分的方法有很多,这篇文章主要是有关牛顿-科特斯公式. 学过插值算法的同学最容易想到的就是用插值函数代替被积分函数来求积分,但实际上在大部分场景下这是行不通的. 插值函数一般是一个不超过n次 ...

  2. Android Material Design之 NavigationView侧滑界面自定义 随笔

    一.侧滑界面Menu自定义: 在menu文件夹下新建activity_main_drawer.xml文件,自定义标题和icon: <?xml version="1.0" en ...

  3. Protobuf使用规范分享

    一.Protobuf 的优点 Protobuf 有如 XML,不过它更小.更快.也更简单.它以高效的二进制方式存储,比 XML 小 3 到 10 倍,快 20 到 100 倍.你可以定义自己的数据结构 ...

  4. Win下最爱效率利器:AutoHotKey

    AutoHotkey是一个windows下的开源.免费.自动化软件工具.它由最初旨在提供键盘快捷键的脚本语言驱动(称为:热键),随着时间的推移演变成一个完整的脚本语言.但你不需要把它想得太深,你只需要 ...

  5. UIApplication和OpenUrl的基于使用方法

    UIApplication实用方法 前言: 本文介绍的方法每一个人在项目都应用过,只是有的时候容易忘记每次都要去百度.因为有些方法在整个项目中可能就只会写一次,基于此我只是做个笔记. 1. 每一个应用 ...

  6. Windows操作系统下tomcat安装版图文教程

    下载tomcat安装文件,官方下载地址是:http://tomcat.apache.org/,本文以tomcat-7.0.26版本为例进行安装过程的说明: 1.双击apache-tomcat-7.0. ...

  7. backup1:开始数据库备份

    数据库备份分为数据文件备份和日志文件备份,数据文件的备份分为:完整备份和差异备份.在SQL Server 2012中,能够将数据分布式备份到不同的存储设备上,一般情况,只将数据备份到一个备份文件(.b ...

  8. Redis数据结构详解(一)

    前言 Redis和Memcached最大的区别,Redis 除啦支持数据持久化之外,还支持更多的数据类型而不仅仅是简单key-value结构的数据记录.Redis还支持对这些数据类型做更多的服务端操作 ...

  9. 在ASP.NET中基于Owin OAuth使用Client Credentials Grant授权发放Token

    OAuth真是一个复杂的东东,即使你把OAuth规范倒背如流,在具体实现时也会无从下手.因此,Microsoft.Owin.Security.OAuth应运而生(它的实现代码在Katana项目中),帮 ...

  10. 给jquery-validation插件添加控件的验证回调方法

    jquery-validation.js在前端验证中使用起来非常方便,提供的功能基本上能满足大部分验证需求,例如:1.内置了很多常用的验证方法:2.可以自定义错误显示信息:3.可以自定义错误显示位置: ...