- A+
1. 什么是Mvc
模型-视图-控制器 (MVC) 体系结构模式将应用程序分成 3 个主要组件组:视图模型、视图和控制器。 此模式有助于实现关注点分离。 使用此模式,用户请求被路由到控制器,后者负责使用模型来执行用户操作和/或检索查询结果。 控制器选择要显示给用户的视图,并为其提供所需的任何模型数据。
下图显示 3 个主要组件及其相互引用关系:
这种责任划分有助于根据复杂性缩放应用程序,因为这更易于编码、调试和测试包含单一作业的某个组成部分(模型、视图或控制器)。 但这会加大更新、测试和调试代码的难度,该代码在这 3 个领域的两个或多个领域间存在依赖关系。 例如,用户界面逻辑的变更频率往往高于业务逻辑。 如果将表示代码和业务逻辑组合在单个对象中,则每次更改用户界面时都必须修改包含业务逻辑的对象。 这常常会引发错误,并且需要在每次进行细微的用户界面更改后重新测试业务逻辑。
视图和控制器均依赖于模型。 但是,模型既不依赖于视图,也不依赖于控制器。 这是分离的一个关键优势。 这种分离允许模型独立于可视化展示进行构建和测试。
模型责任
MVC 应用程序的模型 (M) 表示应用程序和任何应由其执行的业务逻辑或操作的状态。 业务逻辑应与保持应用程序状态的任何实现逻辑一起封装在模型中。 强类型视图通常使用 ViewModel 类型,旨在包含要在该视图上显示的数据。 控制器从模型创建并填充 ViewModel 实例。
视图责任
视图 (V) 负责通过用户界面展示内容。 它们使用 Razor 视图引擎 在 HTML 标记中嵌入 .NET 代码。 视图中应该有最小逻辑,并且其中的任何逻辑都必须与展示内容相关。 如果发现需要在视图文件中执行大量逻辑以显示复杂模型中的数据,请考虑使用 View Component、ViewModel 或视图模板来简化视图。
控制器职责
控制器 (C) 是处理用户交互、使用模型并最终选择要呈现的视图的组件。 在 MVC 应用程序中,视图仅显示信息;控制器处理并响应用户输入和交互。 在 MVC 模式中,控制器是初始入口点,负责选择要使用的模型类型和要呈现的视图(因此得名 - 它控制应用如何响应给定请求)。
备注
控制器不应由于责任过多而变得过于复杂。 要阻止控制器逻辑变得过于复杂,请将业务逻辑推出控制器并推入域模型。
提示
如果发现控制器操作经常执行相同类型的操作,可将这些常见操作移入筛选器。
2. ASP.NET Core MVC
ASP.NET Core MVC 框架是轻量级、开源、高度可测试的演示框架,并针对 ASP.NET Core 进行了优化。它摒弃了传统的全家桶模式,采用了按需所取的方式给用户提供服务。
ASP.NET Core MVC 提供一种基于模式的方式,用于生成可彻底分开管理事务的动态网站。 它提供对标记的完全控制,支持 TDD 友好开发并使用最新的 Web 标准。
1. 与Framework 下的 Asp.Net Mvc 的区别
详细内容: ASP.NET MVC 和 ASP.NET Core 之间的体系结构差异 | Microsoft Docs
差异 | Frameowrk Mvc | Mvc Core |
---|---|---|
体系结构 | 非跨平台 | 跨平台 |
启动方式 | ASP.NET 应用托管在 IIS 中,它们依赖于 IIS 来实例化某些对象,并在请求到达时调用某些方法。 | ASP.NET Core 应用是独立程序。 因此,它们通常包含一个 Program.cs 文件,该文件包含应用的入口点 . |
托管差异 | ASP.NET MVC 应用托管在 IIS 中,并可能依赖 IIS 配置来实现其行为。 这通常包括 IIS 模块。 | 使用了更轻量的kestrel 服务器,它可支持跨平台 |
静态文件 | 由 IIS 托管静态文件。支持将静态文件与应在服务器上保持私有的文件并排放置。(可使用内容分发网络CDN优化) | 不能直接支持,必须配置静态文件中间件。(wwwroot为固定文件夹) |
注入差异 | 需要借助第三方工具,如Autofac,Unity,Ninject... | 内置于框架中,在应用启动时,将调用 ConfigureServices ,该调用负责注册 DI 容器(服务集合/服务提供商)可在应用中创建和注入的所有类型 |
模块和处理程序 | HTTP 模块和 HTTP 处理程序是 ASP.NET 体系结构的必要部分。 处理请求时,每个请求都由多个 HTTP 模块(例如身份验证模块和会话模块)处理,然后由单个 HTTP 处理程序进行处理。 在处理程序处理请求后,请求通过 HTTP 模块传输回去。(全家桶) | ASP.NET Core 在每个应用的 Configure 方法中定义一个请求管道。 此请求管道定义了应用如何处理传入的请求,其中管道中的每个方法都调用下一个方法,直到最终方法终止(按需所用) |
配置差异 | 配置使用应用文件夹中内置的 .NET 配置文件web.config,ConfigurationManager静态访问 | 配置本身是可配置的。可根据需要注入IConfiguration访问配置值 |
2. Mvc:约定大于配置
-
控制器类加Controller后缀,而且都放在Web项目下的Controllers文件夹中,控制器类继承Controller基类。
-
视图文件必须放在名称为Views/Pages 的文件夹下的名称为控制器名称的文件夹中。
-
_ViewStart.cshtml 执行任何Action(控制器中以IActionResult为返回类型的方法叫Action方法)之前,都会先执行它.
-
以下划线命名开头的视图一般作为布局/ViewCompenent 视图,放在shared文件夹下面
-
_ViewImport.cshtm 为全局视图文件共公命名空间的引用
3. 快速入门
-
创建项目
刚新建好的空项目:
-
选中Controllers 文件夹,右键-->新建-->类/接口
-
控制器代码
// Hello 表示控制器名称,HelloController 是控制器类名(C) public class HelloController:Controller { // 创建视图文件的方法(V) public IActionResult Index() { // 业务逻辑,模型操作(M) List<StudentViewModel> list = new List<StudentViewModel>() { new(1,"张三"), // C#9.0 以上创建对象语法 new(2,"李四"), new (3,"王五") }; return View(list);// 将模型数据传递给视图 } } public record StudentViewModel(int Id,string Name);
-
在Views/ 目录下创建Hello目录,在Hello目录下创建Index.cshtml文件。
-
编写任意html代码
@* 接收视图模型传递过来的数据 *@ @model List<WebApplication2.Controllers.StudentViewModel> @{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Mvc 快速入门</title> </head> <body> <div> <h1>大家好,欢迎来到任我行码农场,Asp.net Mvc</h1> </div> </body> </html>
3. Mvc 项目结构
-
Dependencies:项目所依赖的组件
-
launchSettings.json : 项目发布设置文件
{ "iisSettings": {// iis 设置 "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:21843", "sslPort": 44331 } }, "profiles": { "WebApplication2": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true,// 使用浏览器 "applicationUrl": "http://localhost:5096",// 项目运行地址 "environmentVariables": { // 当前环境 "ASPNETCORE_ENVIRONMENT": "Development" // 表示当前环境为Development } }, "IIS Express": { // 内置IIS 的设置 "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } }
-
Controllers: 存放所有的控制器
-
Models: 存放所有的ViewModel 文件
-
Views: 存放所有的视图文件
-
Views/Shared : 存放公共的视图文件
-
Views/Shared/_Layout.cshtml : 公共布局文件
-
Views/Shared/Error.cshtml: 错误提示视图
-
Views/_ViewImports.cshtml: 公共导入命名空间,引用公共的标签助手
@using WebApplication2 @using WebApplication2.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Views/_ViewStart.cshtml: 视图起始文件,所有视图在加载时,都会先加载此视图文件 wwwroot: 存放所有的静态资源文件(css/js/html) wwwroot/favicon.ico : 应用程序的图标 appsetting.json: 当前应用程序的配置文件 appsetting.Development.json: 当前环境的配置文件,如果在此文件中未找到想要的配置,则会去appsetting.json 文件中去寻找。 Program:程序的主入口,用于初始化系统的相关配置,注册服务,配置中间件与注册管道。 4. 控制器动作 控制器动作(具体的action)返回的结果叫做控制器动作结果,动作结果是控制器返回给浏览器请求的内容。ASP.NET Core MVC 框架支持几十种标准类型的动作结果,以下是常见的类型 动作名称 简要概述 ViewResult 返回视图 RedirectToActionResult 重定向到某个Action方法 JsonResult Json结果,可以用于Ajax应用程序 ContentResult 文本结果 RedirectResult 重定向到一个新的URL FileResult 返回一个文件,一般用于下载 它们 都实现了IActionResult 接口。 public ViewResult Index() { List<StudentViewModel> list = new List<StudentViewModel>() { new(1,"张三"), new(2,"李四"), new (3,"王五") }; return View(list); } public JsonResult Index2() { List<StudentViewModel> list = new List<StudentViewModel>() { new(1,"张三"), new(2,"李四"), new (3,"王五") }; return Json(list); } public ContentResult Index3() { return Content("hello,任我行码农场"); } public RedirectToActionResult Index4() { return RedirectToAction("Index2", "Hello"); } public FileResult Download() { using MemoryStream ms = new MemoryStream(); var buffer = Encoding.UTF8.GetBytes("文件下载"); ms.Write(buffer); return File(ms.ToArray(), "application/octet-stream", "测试文件.txt"); }
Action方法与普通方法的区别
Action方法是由Mvc 框架管理,Mvc 框架可以对Action方法进行处理与渲染(例如渲染视图,拦截请求等等),而普通则不受mvc 控制。
举个例子,ContentResult 通常的作用也是直接返回一个字符串,当我们执行Content("hello,任我行码农场")
时,我们只是告诉Mvc框架,我们需要返回 “hello,任我行码农场”
,而并非立即返回,Mvc 框架在此之后可能还会做很多的处理,或许在中间的某个环节,有可能请求被拦截,导致我们可能得到不同的结果(日后要讲的AOPA思想)。而return "hello,任我行码农场"
则是立即返回。
5. Razor视图
注释
@* *@
输出纯文本:
@:这里是妹子可以看的内容
编写C#代码
<html> <head> <title>Mvc 快速入门</title> </head> <body> <div> <h1>大家好,欢迎来到任我行码农场,Asp.net Mvc</h1> @{ int a = 1; int b = 2; Console.WriteLine(a+b); } </div> </body> </html>
if else
<html> <head> <title>Mvc 快速入门</title> </head> <body> <div> <h1>大家好,欢迎来到任我行码农场,Asp.net Mvc</h1> @if (true) { <h1>hello</h1> } else { <p>world</p> } </div> </body> </html>
视图传值
1. TempData
public IActionResult Index() { TempData["username"] = "任我行"; return View(); } <body> <div> <h1>我的名称:@TempData["username"]</h1> </div> </body>
TempData 保存在Session中,Controller每次执行请求的时候,会从Session中先获取 TempData,而后清除Session,获取完TempData数据,虽然保存在内部字典对象中,但是其集合中的每个条目访问一次后就从字典表中删 除。具体代码层面,TempData获取过程是通过SessionStateTempDataProvider.LoadTempData方法从 ControllerContext的Session中读取数据,而后清除Session,故TempData只能跨Controller传递一次。
2.ViewBag 与 ViewData
ViewData:
ViewData 只在当前 Action 中有效,生命周期和 View 相同;
public IActionResult Index() { ViewData["username"] = "任我行"; return View(); } <body> <div> <h1>我的名称:@ViewData["username"]</h1> </div> </body>
ViewBag
ViewBag其实本质就是ViewData,只是多了层Dynamic控制。所以,使用何种方式完全取决于你的个人爱好。
public IActionResult Index() { ViewBag.UserName = "任我行"; return View(); } <body> <div> <h1>我的名称:@ViewBag.UserName</h1> </div> </body>
两者区别如下:
ViewData | ViewBag |
---|---|
它是key/value字典集合 | 它是dynamic类型对象 |
从asp.net mvc1就有了 | 从asp.netmvc3才有 |
基于asp.netframework 3.5 | 基于asp.net framework4.0 |
viewdata比viewbag快 | viewbag比viewdata慢 |
页面查询数据时需要转换合适的类型 | 在页面查询数据时不需要转换合适的类型 |
有一些类型转换代码 | 可读性较好 |
总结
1、ViewData和TempData是字典类型,赋值方式用字典方式,ViewData["myName"]
2、ViewBag是动态类型,使用时直接添加属性赋值即可 ViewBag.myName
3、ViewBag和ViewData只在当前Action中有效,等同于View
4、TempData可以通过转向继续使用(Server.Tranfer()),因为它的值保存在Session中。但TempData只能经过一次传递,之后会被系统自动清除(Framework)
5、ViewData和ViewBag中的值可以互相访问,因为ViewBag的实现中包含了ViewData