Backend - C# asp .net core MVC
目录
一、Controllers 目录
1. 命名空间都是项目名.Controllers。
2. 类名的后缀固定是Controller。
3. [ApiController]
4. [Route("[controller]")]
5. 基类ControllerBase
编辑 二、视图文件
(一).cshtml(视图文件)存储位置:
1. 默认位置
2. 指定其他位置
(二).cshtml(视图文件)快速生成方式:
三、controller的视图方法View()
(一)查找视图文件的三种方法
1. View() 或 View(object model)
2. View(string viewName)
3. View(string viewName, object model )
(二)数据从控制器传递到视图的三种方法
1. ViewData
2. ViewBag
3. 强类型视图(编译时提供类型检查和智能提示)
(三)三种方法的定义和使用例子
1. Book.cs(Models中)
2. Bookcontroller.cs(Controllers中,部分代码)
3. test2.cshtml(Views/Book中)
4. test3.cshtml(Views/Book中)
5. test4.cshtml(Views/Book中)
6. 测试网页路由
① ViewBag测试
② ViewData测试
③ 强类型model测试
四、ViewModel 视图模型
1. 定义视图模型名
2. 作用
3. 强类型的好处
4. 举例
(1)新建ViewModels文件夹,以及子文件BookTestModelViewModel.cs
(2)Bookcontroller.cs(Controllers中,部分代码)
(3)test5.cshtml(Views/Book中)
(4)测试
五、MVC中HTTP请求的常用返回类型
1. IActionResult
2. ViewResult。
3. RedirectResult
4. RedirectToActionResult
5. 举例
六、MVC前端显示列表
1. 新建ViewModels文件夹,以及子文件BookTestModelViewModel.cs
2. Bookcontroller.cs(Controllers中,部分代码)
3. test6.cshtml(Views/Book中)
4. 测试
七、MVC前端模板
1. 命名
2. 位置
3. 文件类型
4. 引用公共页面
5. 具体实现的例子
(1)新建ViewModels文件夹,以及子文件BookTestModelViewModel.cs
(2)Bookcontroller.cs(Controllers中,部分代码)
(3)testchild1.cshtml(Views/Book中)
八、MVC前端模板的RenderSection
1. 作用
2. 共享文件定义时
3. 子页面渲染时
九、MVC中的Razor视图开始文件(视图检视开始)
1. 命名
2. 位置
3. 优先级
4. 作用
十、MVC中Razor视图导入文件(视图检视汇入)
1. 命名
2. 作用
3. 位置
4. 优先级
5. 例子
(1)未使用导入文件时
(2)使用导入文件时
① 某cshtml引入model的写法是:
② 搭配导入文件的内容是:
十一、MVC中的路由
(一)传统路由
(二)属性路由
(三)属性路由(高级写法)
1. 第一种方式
2. 第二种方式
十二、模板href跳转路由
第一种:
第二种:
第三种:(推荐)
十三、Taghelper 跳转链接
(一)作用
(二)引入
(三)举例(生成跳转链接):
1. 写法:
(1)首先配置路由
(2)跳转路由
(3)执行跳转
(4)如果配置的路由发生变化
① 写法
② 执行跳转
十四、模板中引入文件
1. 引入快捷方式
2. 位置
3. 注意
4. 引入样式文件写法
十五、模型绑定顺序
十六、模型绑定注解验证
(一)Model类
(二)cshtml模板文件
(三)Controller类
十七、MVC架构的简单项目例子
(一)实体类(项目名/Models/Book.cs)
(二)模拟存储库的接口(项目名/Models/IBookRepository.cs)
(三)模拟存储库的实体类(项目名/Models/MockBookRepository.cs)
(四)控制器中注入依赖(项目名/Controllers/BookController.cs)
(五)Program.cs 中注册 IBookRepository
(六)测试(浏览器URL中输入)
1. 默认路由
2. 通过bookID获取值
十八、AddMvcCore & AddMvc
一、Controllers 目录
针对Controllers目录下的某个Controller文件内容:
1. 命名空间都是项目名.Controllers。
2. 类名的后缀固定是Controller。
3. [ApiController]
作用是设置该类是一个API控制器。可以自动绑定请求体到方法参数,自动验证不符合要求的数据请求。
4. [Route("[controller]")]
作用是指定路由模板。[controller]是一个占位符,会自动替换成类名(获取类名的前半部分,去掉Controller后缀。如WeatherForecastController中,获取WeatherForecast)。最终组成该控制器的API路径是/weatherforecast,也可以直接设定Route("Book/add"),最终的API路径则是/Book/add)。
5. 基类ControllerBase
作用是提供自动化HTTP请求和响应处理(如Ok())。
二、视图文件
(一).cshtml(视图文件)存储位置:
1. 默认位置
默认目录是 Views / 所在controller名(去掉controller后缀)文件夹里。
在Controller找页面时,用return View();
2. 指定其他位置
一般放在Views目录下,然后再自定义文件夹存放。
在Controller找页面时,用return View("~/Views/XXX/XXX.cshtml"); // 一定要带上文件后缀(.cshtml)
例子:
[Route("authorurl/test")]
public IActionResult testurl2() // 测试路由
{
ViewData["Title"] = "这是路由标题";
ViewData["bookName"] = "这是路由名";
return View("~/Views/Book/TestView.cshtml");
}
(二).cshtml(视图文件)快速生成方式:
在 return View(); 中的 View 单词上右击,选择“新增视图”,在提供的默认配置下直接点击“新增”。
三、controller的视图方法View()
(一)查找视图文件的三种方法
1. View() 或 View(object model)
查找与操作方法相同名称的视图文件。
2. View(string viewName)
查找自定义的视图文件。
可指定绝对路径,但须带上.cshtml后缀。若是相对路径则不用带后缀。
3. View(string viewName, object model )
(二)数据从控制器传递到视图的三种方法
1. ViewData
2. ViewBag
3. 强类型视图(编译时提供类型检查和智能提示)
(三)三种方法的定义和使用例子
1. Book.cs(Models中)
namespace ASPNetAPI.Models
{
public class Book
{
public int BookID { get; set; }
public string BookName { get; set; }
public string Description { get; set; }
public string Author { get; set; }
public double Price { get; set; }
}
}
2. Bookcontroller.cs(Controllers中,部分代码)
public IActionResult TestViewBag() // 用ViewBag测试数据传递
{
Book bookmodel = _bookRepository.GetBook(1);
ViewBag.bookTitle = bookmodel.BookName.ToString() + "(ViewBag)";
ViewBag.bookDetails = bookmodel;
return View("test2");
}
public IActionResult TestViewData() // 用ViewData测试数据传递
{
Book bookmodel = _bookRepository.GetBook(1);
ViewData["bookTitle"] = bookmodel.BookName.ToString() + "(ViewData)";
ViewData["bookDetails"] = bookmodel;
return View("test3");
}
public IActionResult TestViewModel() // 用强类型测试数据传递
{
Book bookmodel = _bookRepository.GetBook(1);
ViewData["bookTitle"] = bookmodel.BookName.ToString() + "(Model)";
return View("test4", bookmodel); // 指定视图文件,传入bookmodel作为强类型
}
3. test2.cshtml(Views/Book中)
@using ASPNetAPI.Models // 引入Book类所需
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ViewBag的使用</title>
</head>
<body>
<h3>@ViewBag.bookTitle</h3>
@{
var books = ViewBag.bookDetails as Book; //显示转换 使用动态属性取值
}
<div>书籍名称 @books.BookName</div>
<div>书籍作者 @books.Author</div>
<div>书籍价格 @books.Price</div>
</body>
</html>
4. test3.cshtml(Views/Book中)
@using ASPNetAPI.Models // 引入Book类所需
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ViewData的使用</title>
</head>
<body>
<h3>@ViewData["bookTitle"]</h3>
@{
var books = ViewData["bookDetails"] as Book; //显示转换 使用字典取值
}
<div>书籍名称 @books.BookName</div>
<div>书籍作者 @books.Author</div>
<div>书籍价格 @books.Price</div>
</body>
</html>
5. test4.cshtml(Views/Book中)
@model ASPNetAPI.Models.Book // 用@model指定模型类型。匹配到Controller文件的view( )传入的bookmodel
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>强类型的使用</title>
</head>
<body>
<h3>@ViewData["bookTitle"]</h3>
<div>书籍名称 @Model.BookName</div><!--固定用@Model访问模型对象属性-->
<div>书籍作者 @Model.Author</div>
<div>书籍价格 @Model.Price</div>
</body>
</html>
6. 测试网页路由
① ViewBag测试
https://localhost:44372/Book/testviewbag
② ViewData测试
https://localhost:44372/Book/testviewdata
③ 强类型model测试
https://localhost:44372/Book/testviewdmodel
四、ViewModel 视图模型
1. 定义视图模型名
一般是:视图名+操作方法名+ViewModel
2. 作用
将所有数据都用模型对象存储,保证所有数据都用强类型视图的方式来获取。
3. 强类型的好处
编译时提供类型检查和智能提示、方便获取和传递数据。
4. 举例
(1)新建ViewModels文件夹,以及子文件BookTestModelViewModel.cs
using ASPNetAPI.Models;
namespace ASPNetAPI.ViewModels
{
public class BookTestModelViewModel
{
public Book Book { get; set; }
public String PageTitle { get; set; }
}
}
(2)Bookcontroller.cs(Controllers中,部分代码)
public IActionResult TestModel() // 测试数据传递(强类型)
{
BookTestModelViewModel bookmodel = new BookTestModelViewModel()
{
Book = _bookRepository.GetBook(1),
PageTitle = "ViewModel测试"
};
return View("test5", bookmodel);
}
(3)test5.cshtml(Views/Book中)
@model ASPNetAPI.ViewModels.BookTestModelViewModel
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>强类型的使用</title>
</head>
<body>
<h3>@Model.PageTitle</h3>
<div>书籍名称 @Model.Book.BookName</div><!--固定用Model-->
<div>书籍作者 @Model.Book.Author</div>
<div>书籍价格 @Model.Book.Price</div>
</body>
</html>
(4)测试
其他文件不变。
测试:https://localhost:44372/Book/TestModel
五、MVC中HTTP请求的常用返回类型
1. IActionResult
理解:是一个接口,定义了所有可能的返回类型。
2. ViewResult。
作用:是 IActionResult 的实现之一,返回视图页面(HTML)
搭配:return View()
3. RedirectResult
作用:将客户端重定向到指定的 URL。
搭配:return Redirect("url")
4. RedirectToActionResult
作用:将请求重定向到控制器的其他动作方法。
搭配:return RedirectToAction("ActionName") 或者return RedirectToAction("操作方法名", new { 参数key = 参数值 });
其中,return使用的是RedirectToAction()指定到方法中,而不是 View()指定到视图中
5. 举例
[HttpPost]
public RedirectToActionResult AddMusic(Music music)
{
Music newMusic = _musicRepository.CreateSong(music);
return RedirectToAction("ShowOneSong", new { id = newMusic.MusicID }); // 注意使用new { id = newMusic.MusicID }。不要直接传递newMusic.MusicID(会导致路由的参数名映射错误)
}
六、MVC前端显示列表
具体实现的例子:
1. 新建ViewModels文件夹,以及子文件BookTestModelViewModel.cs
using ASPNetAPI.Models;
namespace ASPNetAPI.ViewModels
{
public class BookTestEnumerableViewModel
{
public IEnumerable<Book> Books { get; set; }
public String PageTitle { get; set; }
}
}
2. Bookcontroller.cs(Controllers中,部分代码)
public IActionResult TestEnumerable() // 测试数据传递
{
BookTestEnumerableViewModel bookmodel = new BookTestEnumerableViewModel()
{
Books = _bookRepository.GetBooks(),
PageTitle = "Enumerable测试"
};
//ViewData["bookTitle"] = bookmodel.Book.BookName.ToString() + "(Model)";
return View("test6", bookmodel);
}
3. test6.cshtml(Views/Book中)
@model ASPNetAPI.ViewModels.BookTestEnumerableViewModel
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>强类型的使用</title>
</head>
<body>
<h3>@Model.PageTitle</h3>
<table>
<thead>
<tr>
<th>BookID</th>
<th>BookName</th>
<th>Description</th>
<th>Author</th>
<th>Price</th>
</tr>
</thead>
<tbody>
@foreach(var bk in Model.Books){
<tr>
<td>@bk.BookID</td>
<td>@bk.BookName</td>
<td>@bk.Description</td>
<td>@bk.Author</td>
<td>@bk.Price</td>
</tr>
}
</tbody>
</table>
</body>
</html>
4. 测试
其他文件不变。
测试:https://localhost:44372/Book/TestEnumerable
七、MVC前端模板
1. 命名
模板页面的命名都用下划线开头。
2. 位置
一般放在Views/Shared目录中。
3. 文件类型
新增的文件类型是Razor布局(Razor版面配置)。
4. 引用公共页面
子页面通过以下代码引用到公共布局页面。
@{
Layout = "~/views/XXX/_Layout.cshtml"; // 斜杠使用/,而不是\。
ViewBag.Title = "子页面测试";
}
5. 具体实现的例子
(1)新建ViewModels文件夹,以及子文件BookTestModelViewModel.cs
using ASPNetAPI.Models;
namespace ASPNetAPI.ViewModels
{
public class BookTestEnumerableViewModel
{
public IEnumerable<Book> Books { get; set; }
public String PageTitle { get; set; }
}
}
(2)Bookcontroller.cs(Controllers中,部分代码)
public IActionResult TestLayout() // 测试数据传递
{
BookTestEnumerableViewModel bookmodel = new BookTestEnumerableViewModel()
{
Books = _bookRepository.GetBooks(),
PageTitle = "Layout测试"
};
//ViewData["bookTitle"] = bookmodel.Book.BookName.ToString() + "(Model)";
return View("testchild1", bookmodel);
}
(3)testchild1.cshtml(Views/Book中)
@model ASPNetAPI.ViewModels.BookTestEnumerableViewModel
@{
Layout = "~/views/common/_layout.cshtml"; // 斜杠使用/,而不是\。
ViewBag.Title = "子页面测试";
}
<table>
<thead>
<tr>
<th>BookID</th>
<th>BookName</th>
<th>Description</th>
<th>Author</th>
<th>Price</th>
</tr>
</thead>
<tbody>
@foreach (var bk in Model.Books)
{
<tr>
<td>@bk.BookID</td>
<td>@bk.BookName</td>
<td>@bk.Description</td>
<td>@bk.Author</td>
<td>@bk.Price</td>
</tr>
}
</tbody>
</table>
八、MVC前端模板的RenderSection
1. 作用
方便不同的子页面使用不同的JS。
2. 共享文件定义时
@RenderSection("sectionJS", false) // <!--写在模板文件代码的body内最底部,参数1为自定义节点名,参数2为是否必需JS插入文件-->
3. 子页面渲染时
@section sectionJS{
<script src="~/js/common.js"></script> <!--写在要使用某JS的子页面代码的最底部,sectionJS为节点名-->
}
九、MVC中的Razor视图开始文件(视图检视开始)
1. 命名
新建时默认用_ViewStart.cshtml名。
2. 位置
可存储在Views目录里的任何位置。
3. 优先级
内部代码里 > 同层级的_ViewStart.cshtml > 父级的_ViewStart.cshtml
4. 作用
统一处理文件。如统一引入Layout布局模板文件。(每个子页面就不用都引入Layout模板文件,直接在_ViewStart.cshtml中统一管理)
十、MVC中Razor视图导入文件(视图检视汇入)
1. 命名
新建时,默认用_ViewImports.cshtml名。
2. 作用
统一处理命名空间。
3. 位置
可存储在Views目录里的任何位置。
4. 优先级
内部代码里 > 同层级的_ViewImports.cshtml > 父级的_ViewImports.cshtml
5. 例子
(1)未使用导入文件时
某cshtml引入model的写法是:
@model ASPNetAPI.ViewModels.BookViewModel
(2)使用导入文件时
① 某cshtml引入model的写法是:
@model BookViewModel
② 搭配导入文件的内容是:
@using ASPNetAPI.ViewModels;
十一、MVC中的路由
(一)传统路由
// programs.cs中配置路由
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}", // 自定义路由(其中id对应某方法的参数名)
defaults: new { controller = "Book", action = "Index" }); // 默认路由
app.Run();
(二)属性路由
属性路由可以修饰控制器类、控制器的操作方法。
举例(修饰方法):
using Microsoft.AspNetCore.Mvc;
namespace ASPNetAPI.Controllers
{
public class RouteController: Controller
{
[Route("")] // 表示默认路由。直接https://localhost+端口号就可执行该方法
[Route(自定义路径/自定义路径…")] // 路径可自定义
[Route("自定义路径/自定义路径.../{id?}/{name?}")] // 若有参数,参数名必须和方法中的参数名一致(参数名必须一致,参数位置可以任意调换)
// [Route("~/")] // 该方式不要用,含有~,好像会报错。
public string testurl(int id, string name) // 测试路由
{
return "测试路由 id: "+id+"; name: "+ name;
}
}
}
(三)属性路由(高级写法)
该写法的好处是,在重命名控制器或操作方法的名称时,不用再修改路由规则。
1. 第一种方式
类的路由修饰:[Route("[controller]")]
方法的路由修饰: [Route("[action]/{id?}/{name?}")]
using Microsoft.AspNetCore.Mvc;
namespace ASPNetAPI.Controllers
{
[Route("[controller]")]
public class RouteController: Controller
{
[Route("")]
[Route("[action]/{id?}/{name?}")]
public string testurl(int id, string name) // 测试路由
{
return "测试路由 id: "+id+"; name: "+ name??"未指定该参数名";
}
[Route("[action]")]
public IActionResult testurl2() // 测试路由
{
ViewData["Title"] = "这是Route路由标题";
ViewData["bookName"] = "这是Route路由名";
return View("~/Views/Book/TestView.cshtml");
}
}
}
2. 第二种方式
类的路由修饰:[Route("[controller]/[action]")]
方法的路由修饰: [Route("{id?}/{name?}")]
using Microsoft.AspNetCore.Mvc;
namespace ASPNetAPI.Controllers
{
[Route("[controller]/[action]")]
public class RouteController: Controller
{
[Route("")]
[Route("{id?}/{name?}")]
public string testurl(int id, string name) // 测试路由
{
return "测试路由 id: "+id+"; name: "+ name??"未指定该参数名";
}
public IActionResult testurl2() // 测试路由
{
ViewData["Title"] = "这是Route路由标题";
ViewData["bookName"] = "这是Route路由名";
return View("~/Views/Book/TestView.cshtml");
}
}
}
十二、模板href跳转路由
举例:
第一种:
<a href="/music/showonesong/@Model.MusicID" class="btn btn-primary">查看</a>
第二种:
<a href=@Url.Action("showonesong", "music", new{id = mc.MusicID}) class="btn btn-primary">查看</a> <!--Action的参数1是action名,参数2是controller名,参数3是传的值-->
第三种:(推荐)
使用Taghelper的方式。下面章节会讲。
十三、Taghelper 跳转链接
(一)作用
处理HTML。包括生成链接、创建表单、加载数据等。
(二)引入
在_ViewImports.cshtml文件顶部引入addTagHelper组件。
注意引入的代码最后没有分号;
代码写法如下:
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
(三)举例(生成跳转链接):
在前面章节有讲模板href跳转路由的两种常见写法。除此之外,还有一种是使用Taghelper的特性有asp-controller,asp-action,asp-route-id。
使用Taghelper创建跳转路由(生成链接)的好处:programs.cs中的MapControllerRoute配置路由一旦有变,也不会影响跳转路由的当初设定。
1. 写法:
(1)首先配置路由
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}", // 自定义路由
defaults: new { controller = "music", action = "Index" } // 默认路由
);
(2)跳转路由
<a asp-controller="music" asp-action="showonesong" asp-route-id="@Model.MusicID">查看1</a>
<a href="/music/showonesong/@Model.MusicID" class="btn btn-primary">查看2</a>
(3)执行跳转
是https://localhost:44372/music/ShowOneSong/1
(4)如果配置的路由发生变化
① 写法
app.MapControllerRoute(
name: "default",
pattern: "test/{controller}/{action}/{id?}", // 自定义路由(加上了test前缀)
defaults: new { controller = "music", action = "Index" } // 默认路由
);
② 执行跳转
"查看1"的href,通过Taghelper会自动带上test的前缀:https://localhost:44372/test/music/ShowOneSong/1
"查看2"的href,还是不变:https://localhost:44372/music/ShowOneSong/1
十四、模板中引入文件
1. 引入快捷方式
可直接拖动样式文件到代码里,自动生成link文件的代码。
2. 位置
将引入代码放在html模板代码的head内部里。
3. 注意
得用@Url.Content()。
4. 引入样式文件写法
<link href="@Url.Content("~/css/test.css")" rel="stylesheet" />
同理,引入图片文件写法:
<img src="@Url.Content("~/images/car.png")" />
十五、模型绑定顺序
表单中的属性值form values > 路径参数(路由中的值)route values > 查询参数(查询字符串的值)query string。
例如,在执行如下链接时:在https://localhost:44372/music/singer/123/张杰?id=234&name=周深 中,“123/张杰”是路由参数,“?id=234&name=周深”问号后是查询参数。
对应的控制器是:
[HttpGet("/music/singer/{id}/{name}")]
public IActionResult Singer(int id, string name)
{
return Ok(new { Id = id, Name = name }); // 得到的值是123和张杰
}
十六、模型绑定注解验证
(一)Model类
需要引入DataAnnotations:using System.ComponentModel.DataAnnotations;
需要在相应字段上方写模型验证,如[Required] 指定该字段必填,[Display(Name = "XXX")]指定该字段名昵称。
若显示自定义的提示内容,则写法是:[Required(ErrorMessage ="请输入歌名")]
例如:
using System.ComponentModel.DataAnnotations;
namespace ASPNetAPI.Models
{
public class Music
{
public int MusicID { get; set; }
[Required(ErrorMessage ="请输入歌名")]
public string MusicName { get; set; }
public string Description { get; set; }
public string Singer { get; set; }
public int PlayTimes { get; set; }
public double SongPrice { get; set; }
}
}
(二)cshtml模板文件
若显示所有栏位属性的验证错误信息,则在form表单中添加:
<div asp-validation-summary="All"></div>
若显示单个栏位属性的验证错误信息,则在form表单中该栏位属性下添加:
<span asp-validation-for="字段名"></span>
例如:
@model Music
@{
ViewBag.Title = "新增曲目";
}
<form asp-controller="Music" asp-action="AddMusic" method="post" class="mt-3">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="mb-3 row">
<label asp-for="MusicName" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="MusicName" class="form-control" placeholder="请输入歌名" />
<span asp-validation-for="MusicName" class="text-danger"></span>
</div>
</div>
<div class="mb-3 row">
<label asp-for="Description" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="Description" class="form-control" placeholder="请输入备注" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
</div>
<div class="mb-3 row">
<label asp-for="Singer" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<select asp-for="Singer" asp-items="Html.GetEnumSelectList<MusicSingersEnum>()" class="form-select me-sm-2"></select> <!--通过Html获取枚举值-->
</div>
</div>
<div class="mb-3 row">
<div class ="col-sm-10">
<button type="submit" class="btn btn-primary">提交</button>
</div>
</div>
</form>
(三)Controller类
使用ModelState.IsValid进行模型验证。
例如:
[HttpPost]
public IActionResult AddMusic(Music music)
{
if (ModelState.IsValid) // 模型验证
{
Music newMusic = _musicRepository.CreateSong(music);
return RedirectToAction("ShowOneSong", new { id = newMusic.MusicID }); // 注意使用 new { id = newMusic.MusicID },而不是直接传递newMusic.MusicID,直接传递会导致路由参数名映射不对
}
return View();
}
十七、MVC架构的简单项目例子
自建一个模拟数据库,并测试获取该数据库的值。
(一)实体类(项目名/Models/Book.cs)
namespace ASPNetAPI.Models
{
public class Book
{
public int BookID { get; set; }
public string BookName { get; set; }
public string Description { get; set; }
public string Author { get; set; }
public double Price { get; set; }
}
}
(二)模拟存储库的接口(项目名/Models/IBookRepository.cs)
namespace ASPNetAPI.Models
{
public interface IBookRepository
{
Book GetBook(int id);
}
}
(三)模拟存储库的实体类(项目名/Models/MockBookRepository.cs)
namespace ASPNetAPI.Models
{
public class MockBookRepository : IBookRepository
{
private List<Book> _booksList;
public MockBookRepository()
{
_booksList = new List<Book>()
{
new Book() {BookID=1,BookName="数据结构",Author="萝卜",Price=30.0 },
new Book() {BookID=1,BookName="操作系统",Author="派大星",Price=45.5 },
new Book() {BookID=1,BookName="计算机组成原理",Author="海绵宝宝",Price=24.0 },
};
}
public Book GetBook(int id)
{
return _booksList.FirstOrDefault(bk=> bk.BookID==id);
}
}
}
(四)控制器中注入依赖(项目名/Controllers/BookController.cs)
using ASPNetAPI.Models;
using Microsoft.AspNetCore.Mvc;
namespace ASPNetAPI.Controllers
{
public class BookController: Controller
{
private readonly IBookRepository _bookRepository;
public BookController(IBookRepository bookRepository) {
_bookRepository = bookRepository;
}
public string Index()
{
return _bookRepository.GetBook(1).BookName;
}
}
}
(五)Program.cs 中注册 IBookRepository
using ASPNetAPI.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IBookRepository, MockBookRepository>(); // 注册 IBookRepository 和它的实现类 MockBookRepository
builder.Services.AddControllersWithViews(); // 添加 Mvc 服务
var app = builder.Build();
app.MapControllerRoute( // 配置路由, 映射控制器(MVC中间件添加到请求管道中)
name: "default",
pattern: "{controller}/{action}/{id?}", // 自定义路由
defaults: new { controller = "Book", action = "Index" }); // 默认路由
app.Run(); // 启动程式
(六)测试(浏览器URL中输入)
1. 默认路由
https://localhost:44372/或者https://localhost:44372/Book/Index
2. 通过bookID获取值
https://localhost:44372/Book/ByBookID/2
十八、AddMvcCore & AddMvc
AddMvcCore:只提供了最核心的MVC服务。AddMvc添加了所有MVC服务(包含了第三方常用服务,内部会调用AddMvcCore)