ASP.NET MVC
是一个适用于 WEB 应用程序的经典模型 Model-View-Controller
模式。相对于 Web Forms
一个单一的整体,ASP.NET MVC
是由连接在一起的各种代码层所组成。
Global.asax
文件
Global.asax
文件概述
Global.asax
这个文件包含全局应用程序事件的事件处理程序。它响应应用程序级别和会话级别事件的代码。
运行时, Global.asax
将被编译成一个动态生成的 .NET Framework
类,该类是从 HttpApplication
基类派生的。
因此在 Global.asax
中的代码可以访问 HttpApplication
类中所有的 public
或者 protected
的成员。
Global.asax
不被用户直接请求,但 Global.asax
中的代码会被自动执行来响应特定的应用程序事件。
Global.asax
是可选的,而且在一个 web 项目中是唯一的,它应该处于网站的根目录。
一个请求的完整处理过程
以下过程由 Internet Information Service(inetinfo.exe)—— IIS
执行:
- 客户端发出请求
- 验证请求
- 给请求授权
- 确定请求的缓存
- 获取缓存状态
- 在请求的处理程序执行前
- http 处理程序执行请求 (
asp.net
页面由aspnet_wp.exe
执行) - 在请求的处理程序执行后
- 释放请求状态
- 更新请求缓存
- 请求结束
Global.asax
中的事件
Global.asax
中的所有事件可以分成两种,一种是满足特定事件时才会被触发,一种是每次请求都会被按照顺序执行的事件。
1 | using System; |
路由 Routing
ASP.NET MVC
不再是要依赖于物理页面,我们可以使用自己的语法自定义 URL,通过这些语法来指定资源和操作。语法通过 URL 模式集合表达,也称为路由。
路由是代表 URL 绝对路径的模式匹配字符串。所以路由可以是一个常量字符串,也可能包含一些占位符。
新建一个 ASP.NET MVC
项目,在 Global.asax
文件我们可以看到路由在这里注册,让程序在启动的时候得到处理。
1 | RouteConfig.RegisterRoutes(RouteTable.Routes);//注册 Route |
转到定义可以看到注册的规则:
1 | public class RouteConfig |
注意:因为匹配路由是按照添加顺序去解析,所以基本的路由规则是从特殊到一般排列,否则可能导致解析异常或 404 Not Found。
具体配置参考文章:史上最全的 ASP.NET MVC 路由配置 与 Attribute Routing in ASP.NET MVC 5。
控制器 Controller
ASP.NET MVC
会调用不同的控制器类(和其内部不同的操作方法)这取决于传入 URL。所使用的 ASP.NET MVC
的默认 URL 路由逻辑使用这样的格式来判定哪些代码以便调用:/[Controller]/[ActionName]/[Parameters]
。
项目建立以后有一个默认的控制器 \Controllers\HomeController.cs
1 | public class HomeController : Controller |
在 Controllers
文件夹右键 -> 添加 可以看到创建控制器的选项。
控制器每一个方法为一个 Action
,每个 Action
对应的是项目内 \Views\[Controller]\[ActionName].cshml
,在方法内右键,菜单有“添加视图”与“转到视图”选项。
ActionResult
返回值
(一)视图类型
返回视图:
1 | public ActionResult Index() |
返回分部视图:
1 | public ActionResult ViewTest() |
注意: 以上均需要对 Action
添加视图文件,若无 Action
方法的视图文件也可以直接通过视图名称或视图路径指定视图文件,具体可以查看 View()
方法重载。
(二)文本类型
返回 JavaScript
脚本:
1 | public ActionResult ContentJS() |
返回 CSS
样式:
1 | public ActionResult ContentCSS() |
(三)JSON
类型
1 | public ActionResult JsonTest() |
(四)图片多媒体类型
1 | public ActionResult ImageTest(string id) |
(五)Javascript
脚本类型
1 | public ActionResult JavaScriptTest() |
(六)文件类型(下载)
1 | public ActionResult FileTest(string id) |
注意:
FileContentResult
:是针对文件内容创建的FileResult
,它只是调用当前HttpResponse
的OutputStream
属性的Write
方法直接将表示文件内容的字节数组写入响应输出流。FilePathResult
:是一个根据物理文件路径创建FileResult
。FileStreamResult
:允许我们通过一个用于读取文件内容的流来创建FileResult
。
可以参考: 了解 ASP.NET MVC 几种 ActionResult 的本质:FileResult
(七)返回 null
或者 void
1 | public ActionResult Empty() |
(八)返回未经授权浏览状态
1 | public ActionResult HttpUnauthorizedResult() |
注意: 响应给客户端错误代码 401
(未经授权浏览状态),如果程序启用了 Forms
验证,并且客户端没有任何身份票据,则会跳转到指定的登录页。
(九)页面跳转
1 | public ActionResult Redirect() |
RedirectToRouteResult
:直接使用Action Name
进行跳转,也可以加上ControllerName
以及参数。RedirectToActionResult
:指定路由进行跳转。
1 | public ActionResult RedirectActionResult() |
总结: 这些返回类型的共同点,那便是对 Action
有一定的要求:
- 必须是一个
public
方法 - 必须是实例方法
- 不能被重载
- 必须返回
ActionResult
类型
视图 View
Views 文件夹下常用文件种类
文件类型 | 扩展名 | 概述 |
---|---|---|
HTML |
.html 或 htm |
静态 html 文件;在开发中通用性最高的页面; 属于 ASP.NET MVC 常用页面; |
Razor 文件 |
.cshtml |
动态 MVC Razor 文件;ASP.NET MVC 中,属于常用文件;采用 Razor 语法格式; 基本取代 .aspx 文件; |
WebForm 文件 |
.aspx |
动态 ASPX 文件;属于 WebForm 架构文件;在 ASP.NET MVC 中,也可以用该页面布局页面但不推荐;在 ASP.NET MVC 中基本被 cshtml 文件取代 |
ASP 文件 |
.asp |
传统 ASP 文件,目前已过时;发展: asp =>aspx =>cshtml ;对应架构: ASP =>ASP.NET WebForm =>ASP.NET MVC |
分析:
ASP.NET MVC
页面基本被放在 Views 文件夹下;- 利用
ASP.NET MVC
模板生成框架,Views 文件夹下的默认页面为.cshtml
页面; ASP.NET MVC
默认页面为 Razor 格式的页面,因此默认页面为.cshtml
页面;ASP.NET MVC
中,支持 WebForm 页面,即.aspx
页面;ASP.NET MVC
中,支持静态 html 页面;
默认 Views 文件夹包含内容
文件夹名称 | 概述 |
---|---|
Account 文件夹 |
包含用于注册并登录用户账户的页面 |
Home 文件夹 |
存储首页和 About 页面信息 |
Share 文件夹 |
存储控制器间分享的视图,如布局页面和模板页等 |
_ViewStart.cshtml |
程序最开始执行的页面 |
分析:
- 这里没添加
Account
控制器; - 默认约定:在
Controllers
新增一个控制器,就会默认地在Views
文件夹下新增一个视图文件夹,用来存放该控制器添加的视图,如上图中增加Home
控制器,在Views
下就自动新增加Home
文件,用来存放是Home
控制器视图;
视图种类
(一)起始视图:_ViewStart.cshtml
1 | @*@{ |
浏览 http://127.0.0.1/Home/Index
(二)布局视图:_Layout.cshtml
首先将 _ViewStart.cshtml
文件还原修改其指向的 _LayoutDemo.cshtml
文件
1 | @{ |
添加 _LayoutDemo.cshtml
文件
1 | @{ |
重新浏览 http://127.0.0.1/Home/Index
_Layout.cshtml
基本结构就是 HTML 基本结构(其实.aspx
和.cshtml
结构,均是 html 结构);- 在
_LayoutDemo.cshtml
文件一个后台代码:@RenderBody()
。@RenderBody()
表示视图体,此外还有@RenderSection()
表示部分视图和节点;
(三)弱类型视图
Controller 向 View 传递少量数据,一般情况,我们可以归为两大类别:弱类别传递(ViewBag,ViewData,TempData)和强类别传递(强类型视图)。然而,在实际操作中,当涉及大量数据时,弱类别就显得不是那么方便,此时,一般采用强类型视图。强类型视图一般由三部分构成,即控制器层,视图层和模型层,三者之间调用关系可表示为:
(1)ViewData 和 TempData
ViewData 只在当前 Action 中有效,生命周期和 View 相同;
TempData 的数据至多只能经过一次 Controller 传递,并且每个元素至多只能被访问一次,访问以后,自动被删除。
TempData 一般用于临时的缓存内容或抛出错误页面时传递错误信息,可以将 TempData 在使用之前存储到相应的 ViewData 中以备循环使用。
TempData 保存在 Session 中,Controller 每次执行请求的时候,会从 Session 中先获取 TempData,而后清除 Session,获取完 TempData 数据,虽然保存在内部字典对象中,但是其集合中的每个条目访问一次后就从字典表中删除。具体代码层面,TempData 获取过程是通过 SessionStateTempDataProvider.LoadTempData 方法从 ControllerContext 的 Session 中读取数据,而后清除 Session,故 TempData 只能跨 Controller 传递一次。
HomeController.cs
1 | public ActionResult Index() |
Index.cshtml 文件
1 | 姓名:@ViewData["myName"] |
About.cshtml 文件
1 | 姓名:@ViewData["myName"] |
(2)ViewBag 和 ViewData
1 | ViewBag.Name = ViewData["Name"]; |
ViewData | ViewBag |
---|---|
Key/Value 集合 | dynamic 类型对象 |
ASP.NET MVC 1 就有 |
ASP.NET MVC 3 才有 |
基于 ASP.NET 3.5 |
基于 ASP.NET 4.0 与 .NET Framework |
ViewData 较快 | ViewBag 较慢 |
视图中查询数据需要转换合适的类型 | 视图中查询数据不需要类型转换 |
有一些类型转换代码 | 可读性好 |
(四)强类型视图
增加实体类 UserInfo.cs
1 | using System; |
HomeController.cs 增加 Action 方法
1 | public ActionResult ModelTest() |
增加视图 ModelTest.cshtml
1 | @model IEnumerable<JohnSun.MVC5.Web.Models.UserInfo> |
运行效果:
(五)分布页
我们在 /Views/Shared
文件夹下创建一个分布页 _PartialPageDemo.cshtml
,并向该页面中添加一段代码:
1 | <h1 style="color:red;">我是分布页</h1> |
在 HomeController.cs 文件中增加返回视图的方法
1 | public ActionResult TestPartialPage() |
在 /Views/Home 增加对应视图文件 TestPartialPage.cshtml
1 | <h1 style="color:red;">我是供控制器调用的分布页</h1> |
在 Index.cshtml 中调用
1 | @{ |
显示效果如下:
调用分布页的几种方式:
- @Html.Partial() 提供分布页路径
- @Html.Action() 提供控制器返回视图的方法
- 通过 Ajax 方式调用
区域 Area
ASP.NET MVC
有预定义的目录规则,框架根据这些目录规则去加载各种类。
在 MVC 单项目中,随着业务越来越复杂多样,我们会希望按照功能对代码按文件夹分门别类。
如果在默认的目录结构下业务混合,这样不方便管理和维护;如果另开新项目,又比较散乱。那么 MVC 有没有这样一种机制来相对独立这些模块呢?答案是肯定的,这就是 MVC 的 Area 区域技术,用来实现在一个 MVC 项目中组织和维护多个相对独立的模块。
在 VS 中右键单击项目,在弹出的菜单中选择“添加 (A)”->“Area…”,在弹出的对话框中输入区域名称(遵守 C# 标示符命名规则)即可(比如输入 System),VS 将自动在根目录创建 Areas 文件夹,此文件夹下每个独立的 Area 一个文件夹,System 文件夹内也是一样的 Models、Controllers、Views 结构。
唯一不同的是多了一个 SystemAreaRegistration.cs
(区域注册类),用于向 MVC 框架注册路由等信息,Global.asax.cs
中会自动调用该类的 RegisterArea 方法。新建 Area 后 VS 自动创建相关目录结构,按需修改 SystemAreaRegistration 路由即可。
1 | using System.Web.Mvc; |
注意: 当 Area 中控制器与 MVC 中控制器同名,比如 HomeController,此时访问首页会异常提示:找到多个与名为“Home”的控制器匹配的类型。如果为此请求({controller}/{action}/{id}
)提供服务的路由没有指定命名空间以搜索与此请求相匹配的控制器,则会发生这种情况。如果是这样,请通过调用带有 namespaces
参数的 MapRoute
方法的重载来注册此路由。
此时修改 RouteConfig.cs 文件中注册路由的方法,添加 HomeController 的命名空间指向即可。
1 | routes.MapRoute( |