上一篇笔记我们学习了ASP.NET Core中控制器的用法,这篇笔记我们继续学习如何在ASP.NET Core中使用MVC开发模式开发完整的网站页面。当然,如今Web开发中的后端MVC模式可能趋于非主流和淘汰,但MVC仍然是ASP.NET Core中占很大功能比例的一部分,如果不想学习MVC相关的内容,可以跳过本章和后续Razor模板引擎相关的章节。
这里我们直接以一个例子的形式展示如何在ASP.NET Core中使用MVC开发模式输出网站页面。
Gacfox.Demo.DemoMVC
|_Models
|_Student.cs
|_Controllers
|_DemoController.cs
|_Views
|_Demo
|_Index.cshtml
下面代码我们定义了MVC中的模型,它就是一个简单的C#类,其中包含了一些数据字段。
Student.cs
namespace Gacfox.Demo.DemoMVC.Models;
public class Student
{
public long Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public DateTime CreateTime { get; set; }
}
下面代码我们定义了MVC中的控制器,我们的控制器继承Controller
类,Index()
方法中我们创建了Student
类并将其绑定到了视图。
DemoController.cs
using Gacfox.Demo.DemoMVC.Models;
using Microsoft.AspNetCore.Mvc;
namespace Gacfox.Demo.DemoMVC.Controllers;
[Route("[controller]")]
public class DemoController : Controller
{
[HttpGet]
[Route("[action]")]
public IActionResult Index()
{
Student s = new() { Id = 1L, Name = "汤姆", Age = 18, CreateTime = DateTime.Now };
return View(s);
}
}
代码中我们调用了View()
方法,它有两个作用:将模型绑定到视图,以及返回视图响应。View()
方法的返回值是ViewResult
,它是IActionResult
的派生类,表示返回的内容是视图页面。
下面代码是我们的视图页面,ASP.NET Core中,视图采用Razor模板引擎,它可以看作一种HTML的扩展,代码的编写要符合Razor的语法。
Index.cshtml
@model Gacfox.Demo.DemoMVC.Models.Student
@{
}
<h1>欢迎,@Model.Name 同学!</h1>
<table>
<tr>
<td>ID</td>
<td>@Model.Id</td>
</tr>
<tr>
<td>姓名</td>
<td>@Model.Name</td>
</tr>
<tr>
<td>年龄</td>
<td>@Model.Age</td>
</tr>
<tr>
<td>入学时间</td>
<td>@Model.CreateTime.ToString("yyyy-MM-dd")</td>
</tr>
</table>
代码中,我们首先声明@model Gacfox.Demo.DemoMVC.Models.Student
绑定模型类到该视图,具体的页面模板代码中,我们使用@Model
的形式访问模型实例对象,对于日期我们还特意调用了ToString()
方法将其按照模板格式化输出。
最终运行后访问效果如下:
此时,我们就完整的实现了一个简单的MVC模式页面。
前面例子中,我们通过如下方式从控制器方法向视图层传递数据:
[HttpGet]
[Route("[action]")]
public IActionResult Index()
{
Student s = new() { Id = 1L, Name = "汤姆", Age = 18, CreateTime = DateTime.Now };
return View(s);
}
上面代码我们直接用View()
方法绑定了Student
的实例对象到视图层,Razor视图层使用@model Gacfox.Demo.DemoMVC.Models.Student
声明绑定模型后,具体HTML中使用@Model
访问模型对象。这是最简单也最推荐的方式,不过除此之外还有一些其它的方式可以使用。
上面方式只能绑定一个模型给视图,如果有多个对象要向视图层传递,可以采用ViewBag
。ViewBag
是Controller
类中的一个dynamic
类型的属性,我们可以将多个对象作为ViewBag
的属性一起传给视图,下面是一个例子。
[HttpGet]
[Route("[action]")]
public IActionResult Index()
{
Student s = new() { Id = 1L, Name = "汤姆", Age = 18, CreateTime = DateTime.Now };
ViewBag.Student = s;
ViewBag.TeacherName = "泰菲";
return View();
}
<p>@ViewBag.Student.Name</p>
<p>@ViewBag.TeacherName</p>
控制器中,我们直接操作ViewBag
对其添加新的属性,视图中我们可以使用@ViewBag
访问其中的内容。
当然,使用ViewBag
的缺点也很明显,它是弱类型的,一些类型错误无法及时被发现,开发过程中IDE也无法给出提示。
MVC开发模式中,有时我们需要使用重定向,比如系统报错时重定向到错误页面,或者访问一个页面时重定向到无权限的提示页面。下面是实现重定向的例子。
[HttpGet]
[Route("Execute")]
public IActionResult Execute()
{
return Redirect("/Demo/ExecuteResult?errMsg=" + HttpUtility.UrlEncode("系统炸了!!!"));
}
代码中,我们使用Redirect()
方法发出重定向请求,它会由服务端返回HTTP302来实现重定向,它的参数是重定向的URL,这里我们手动给URL拼接了一个errMsg
参数作为回显的信息。接收该请求的控制器如下。
[HttpGet]
[Route("ExecuteResult")]
public IActionResult ExecuteResult(string errMsg)
{
ViewBag.ErrMsg = errMsg;
return View();
}
<h1>@ViewBag.ErrMsg</h1>
代码中,我们读取了errMsg
参数并将其传递给视图。
这种方式可能有些缺点,我们将重定向传递的数据放在了URL参数中,如果数据比较多这种方式就不合适了,另一个比较好的实现方式是采用TempData
。
[HttpGet]
[Route("Execute")]
public IActionResult Execute()
{
TempData.Add("ErrMsg", "系统炸了!!!");
return Redirect("/Demo/ExecuteResult");
}
[HttpGet]
[Route("ExecuteResult")]
public IActionResult ExecuteResult()
{
return View();
}
<h1>@TempData["ErrMsg"]</h1>
类似ViewBag
,TempData
也是Controller
类中的一个属性,它也能够用于向视图传递数据,但TempData
是存储在Session中的,它具有只能取一次,取出后TempData
中对应的数据就被清理的特性,基于TempData
上面代码实现了不使用URL传递重定向参数的目的。
ASP.NET Core MVC中,视图层有一些名字以下划线_
开头的特殊文件存在特殊用途。
|_Views
|_ _ViewStart.cshtml
|_ _ViewImports.cshtml
|_Shared
|_ _Layout.cshtml
|_ _ValidationScriptsPartial.cshtml
_ViewStart.cshtml
:用于在每个Razor视图之前执行一些通用的代码,例如设置默认布局和全局视图属性_ViewImports.cshtml
:用于导入命名空间和引用TagHelper。_Layout.cshtml
:用于定义网站的整体布局,包括页眉、页脚、导航菜单等。_ValidationScriptsPartial.cshtml
:用于包含客户端验证脚本,以支持ASP.NET Core的模型验证。这些文件虽然看起来很复杂难记,但它们其实在创建ASP.NET Core MVC工程时会自动创建好,我们对其了解并能够按需修改即可,这里就不过多介绍了。