EF-Core和LINQ编程技术
Q7nl1s admin

模型验证

◼ ASP.NET Core的验证技术是在模型类中以声明方式(注解)指定验证规则,并且在应用中的所 有位置强制执行:

​ ◼ 减少将无效数据保存到数据库的几率

​ ◼ 提升应用的可靠性

常用验证说明

[Required]:验证字段是否不为 null

[StringLength]:验证字符串属性值是否不超过指定的长度限制。

[Range]:验证属性值是否位于指定范围内。

[Compare]:验证模型中的两个属性是否匹配。

[RegularExpression]:验证 属性值是否与指定的正则表达式匹配。

[EmailAddress]:验证属性是否具有电子邮件格式。

注:[DataType]:只是帮助字段进行格式设置,不提供任何验证

示例:模型添加验证 – 后列注释部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Movie
{
public int Id { get; set; } // 电影id

[Required(ErrorMessage = "电影名称必填")] // 必填验证
[StringLength(20, MinimumLength = 3,ErrorMessage ="3-20个字符")] // 字符串长度验证
[Display(Name = "电影名称")]
public string? Title { get; set; } // 电影名称

[Required(ErrorMessage = "上映日期必填")] // 必填验证
[Display(Name = "上映日期")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; } //上映日期

[Required(ErrorMessage = "电影类型必填")] // 必填验证
[StringLength(10, MinimumLength = 2, ErrorMessage = "2-10个字符以内")]// 字符串长度验证
[Display(Name = "电影类型")]
public string? Genre { get; set; } //电影类型

[Required(ErrorMessage = "电影票价必填")] // 必填验证
[Range(1, 100,ErrorMessage ="1-100之间")] // 取值范围验证
[Display(Name = "票价")]
[DataType(DataType.Currency)]
public decimal Price { get; set; } //电影票价
}

验证测试运行:新建数据

E_L_0

强类型传值

◼ 回顾:ViewData 字典传值是一个弱类型传值方式 (使用时需要手工强转类型)

◼ 强类型传值则不需要手工强转类型

◼ 如何实现强类型传值:

​ ① 控制器在返回视图时,添加模型对象作为参数,即: return View(模型对象);

​ ② 在视图中,先使用 @model 指令声明模型对象类型

​ ③ 然后在视图中使用Model对象来接收传来的模型对象,之后使用Model对象无需强转


强类型传值方式1:单值情况

控制器

1
2
3
4
5
6
public IActionResult Test( )
{
// 创建一个模型对象
Movie movie = _context.Movie.Find(1); // 含义:从Movie表中查找id=1的对象
return View(movie); // ① 将Movie模型对象传递给视图(强类型传值)
}

新建Test视图

Test视图

1
2
3
4
@model MvcMovie.Models.Movie	@*  ② 先用"@model"指令声明模型类型 *@

<p>@Model.Title</p> <!-- ③使用Model对象来接收传来的模型对象Model无需强转就可使用,如读取对象属性值 -->
...

运行情况:

E_L_1


强类型传值方式2:多值 (集合) 情况

控制器

1
2
3
4
5
public IActionResult Test( )
{
List<Movie> movies = _context.Movie.ToList(); // 含义:查询Movie表所有对象
return View(movies); // ① 将List<Movie>集合对象传递给视图(强类型传值)
}

修改Test视图

Test视图

1
2
3
4
5
6
@model IEnumerable<MvcMovie.Models.Movie>
...
@foreach ( var item in Model ) // ③使用Model对象来接收传来的集合对象,Model无需强转就可使用,如遍历集合
{
...处理 item
}

◼ 注:IEnumerable<> 是一个集合类泛型接口,是 List<> 的父类


示例:使用表格显示集合数据

Test视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@model IEnumerable
<MvcMovie.Models.Movie>
<table class="table table-striped"> // Bootstrap提供的样式
<tr>
<th>电影名称</th>
<th>电影类型</th>
<th>上映日期</th>
<th>票价</th>
<th colspan="2">操作</th>
</tr>
@foreach (var m in Model) { // foreach循环遍历集合数据,C#支持var隐式类型,会自动右侧表达式推断变量的类型
<tr>
<td>@m.Title</td>
<td>@m.Genre</td>
<td>@m.ReleaseDate</td>
<td>@m.Price</td>
<td><a href="Edit/@m.Id">编辑</a></td>
<td><a href="Delete/@m.Id">删除</a></td> // 此句包含id参数,Edit、Delete是基架自动生成的操作,可以直接使用
</tr>
}
</table>

运行情况:

E_L_2


LINQ查询

◼ LINQ:是Language Integrated Query的简称(语言集成查询),是一系列直接将查询功能集成到 C# 语言的技术统称。

◼ LINQ:能以与查询数据库相似的方式来查询内存数据。

E_L_3

◼ LINQ深入学习:https://docs.microsoft.com/zh-cn/dotnet/csharp/linq/


LINQ查询示例1:Linq To Objects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public string Test1()
{
int[] scores = new int[] { 97, 85, 92, 81, 60 }; //定义int数组
IEnumerable<int> query = // 可用var代替
// 以下四行语句即为LINQ查询
from s in scores //必须
where s > 80 //条件,可选
orderby s descending //排序可选,descending降序,ascending升序(默认)
select s; //必须
string tmp = "";
foreach ( int i in query ) //遍历查询的结果集
{
tmp += i + " ";
}
return tmp;
}

上面查询中LINQ查询的功能:查询值>80的元素,并按降序排序

E_L_4

LINQ查询示例2:Linq To Objects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public string Test1()
{
string[] instructors = { "Aaron", "Jane", "Fritz", "Keith", "Scott", "Tom" }; //定义string数组
IEnumerable<string> query = // 可用var代替
// 以下四行语句即为LINQ查询
from s in instructors //必须
where s.Length == 5 //条件,可选
orderby s descending //排序可选,descending降序,ascending升序(默认)
select s; //必须
string tmp = "";
foreach (string i in query ) //遍历查询的结果集
{
tmp += i + " ";
}
return tmp;
}

功能:查询字符串长度==5的元素,并按降序排序

E_L_5

LINQ查询示例3:Linq To SQL

1
2
3
4
5
6
7
8
9
10
public IActionResult Test3()
{
string searchString = "剧情"; //电影类型
var query =
from s in _context.Movie //查询Movie表
where s.Genre.Contains(searchString) //电影类型(Genre)包含
orderby s.Id //按电影id升序排序
select s;
return View( query );
}

功能:查询类型为”剧情”的电影,并按 id 升序排序

Test3视图代码:

1
2
3
4
5
6
7
8
9
10
11
12
@model IEnumerable<MvcMovie.Models.Movie>

<h4>查询结果</h4>

@foreach ( var m in Model ) {
<p>ID序号:@m.Id</p>
<p>电影名称:@m.Title</p>
<p>电影类型:@m.Genre</p>
<p>上映日期:@m.ReleaseDate</p>
<p>票价:@m.Price</p>
<hr />
}
E_L_6

LINQ查询示例4:配合form表单E_L_7

(1)修改Index代码:注释原来的代码

MoviesController.cs

1
2
3
4
5
6
7
8
9
10
11
public async Task<IActionResult> Index( string searchString )	// 接收查询串
{
if ( String.IsNullOrEmpty(searchString) )
{
searchString = ""; // 查询串如果为null或空串,就置为空串
}
var movies = from m in _context.Movie
where m.Title.Contains(searchString)
select m;
return View( await movies.ToListAsync() ); // ToListAsync():将查询结果集转为List<Movie>集合
}

说明:async Task/await 是 C# 异步编程模式

了解异步编程模式:async Task/await

◼ async Task/await 是一种异步/等待任务编程模式

◼ 优势:更有效地利用服务器资源,并且服务器可以无延迟地处理更多流量

◼ 只有导致查询或发送数据库命令的语句才能以异步方式执行,包括:

ToListAsync、SingleOrDefaultAsync、FirstOrDefaultAsync 和 SaveChangesAsync。


(2)修改Index视图:添加查询表单

注:代码放在Index视图标签前面

Index.cshtml

1
2
3
4
5
6
<form asp-controller="Movies" asp-action="Index" method="get">	<!-- 查询使用HTTP GET请求方式 -->
<p>
电影名称: <input type="text" name="searchString"> <!-- 强调:name属性值必须和后台Action参数名保持一致 -->
<input type="submit" value="查询" />
</p>
</form>

CRUD编程

控制器代码

MoviesController.cs

1
2
3
4
5
6
7
8
9
10
11
public class MoviesController : Controller
{
private readonly MvcMovieContext _context; // 声明数据库上下文对象(私有只读成员变量)

public MoviesController(MvcMovieContext context) // 构造函数,实现将数据库上下文实例注入到控制器中
{
_context = context; // 初始化数据库上下文对象
}

// ...CRUD操作
}

回顾:数据库上下文类作用:封装与数据库和模型相关的功能,依据数据实体状态创建SQL命令,将数据更新保存到数据库中


查询所有 – Index

E_L_8

Index代码:原来的

1
2
3
4
5
6
public async Task<IActionResult> Index()	// 异步任务封装的 IActionResult
{
return _context.Movie != null ? // 问号表达式
View(await _context.Movie.ToListAsync()) :
Problem("Entity set 'MvcMovieContext.Movie' is null."); // 如果Movie集合为null,则报错
}

◼ _context.Movie:读取Movie集合所有数据,返回类型是 DbSet 集合

◼ ToListAsync():将 DbSet 集合转为 List 集合

Index视图代码

Index.cshtml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@model IEnumerable<MvcMovie.Models.Movie>	@* @model命令:声明视图Model对象的类型(强类型,多值) *@
@{
ViewData["Title"] = "Index";
}

<h1>Index</h1>
<p> <a asp-action="Create">Create New</a> </p> <!-- 生成为<a href="/Movies/Create">Create</a> -->
<table class="table">
<thead>
<tr>
<th> @Html.DisplayNameFor(model => model.Title) </th> <!-- model => model.Title 为 lambda表达式 -->
<th> @Html.DisplayNameFor(model => model.ReleaseDate) </th>
<th> @Html.DisplayNameFor(model => model.Genre) </th>
<th> @Html.DisplayNameFor(model => model.Price) </th> <!-- @Html.DisplayNameFor用于显示属性的Display值(中文值) -->
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) { // 遍历Model
<tr>
<td> @Html.DisplayFor(modelItem => item.Title) </td> <!-- @Html.DisplayFor用于显示属性的值 -->
<td> @Html.DisplayFor(modelItem => item.ReleaseDate) </td>
<td> @Html.DisplayFor(modelItem => item.Genre) </td>
<td> @Html.DisplayFor(modelItem => item.Price) </td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
<!--
上面三个<a>将生成为:
<a href="/Movies/Edit/id值">Edit</a>
<a href="/Movies/Details/id值">Edit</a>
<a href="/Movies/Delete/id值">Edit</a>
id值由具体对象确定
-->
</td>
</tr>
}
</tbody>
</table>

用法说明

<a asp-action="Edit" asp-route-id="@item.Id">Edit</a>

◼ *asp-:使用 TagHelpers 技术来动态生成 HTML 属性

◼ TagHelpers 技术基本用法见【附录1】

@Html.DisplayNameFor(model => model.Title)

@Html.DisplayFor(modelItem => item.Title)

@Html.方法():使用 HtmlHelper 类动态创建 HTML 标签或字符串

◼ HtmlHelper类 基本用法见【附录2】


添加操作 – Create

有两个Create操作

E_L_9

第一个Create代码(功能:打开新建界面,用户进行数据录入)

1
2
3
4
public IActionResult Create()
{
return View(); // 返回Create.cshtml视图
}

Create视图代码

Create.cshtml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@model MvcMovie.Models.Movie	//@model命令:强类型,传单值(思考一下:第一个Create并传值为何视图要加@model?)
@{
ViewData["Title"] = "Create";
}

<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create"> <!-- form表单,将生成 action="/Movies/Create" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span> <!-- asp-validation-for 显示模型的验证信息 -->
</div>
<div class="form-group">
<label asp-for="ReleaseDate" class="control-label"></label>
<input asp-for="ReleaseDate" class="form-control" />
<span asp-validation-for="ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" /> <!-- 提交按钮 -->
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>

@section Scripts { // JS代码放在Scripts节中
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");} // 加载"_ValidationScriptsPartial"局部视图,该视图加载了支持验证功能的JS库
}

Tag Helpers技术参考见【附录1】


第二个Create代码(功能:将新建数据提交保存到数据库)

1
2
3
4
5
6
7
8
9
10
11
12
13
// 本页3个注解说明见下页
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create( [Bind("Id,Title,ReleaseDate,Genre,Price")] Movie movie ) // 一次接收数据并封装成Movie对象(更简洁)
{
if ( ModelState.IsValid ) // 检查模型状态是否通过有效 (如果提交的数据通过验证,则为true,否则false)
{
_context.Add(movie);
await _context.SaveChangesAsync();
return RedirectToAction( nameof(Index) ); // 重定向(跳转)到Index (见下页说明)
}
return View( movie ); // 数据没有通过验证时,则将数据返回Create视图重新编辑(强类型传值)
}

_context.Add():调用数据库上下文的Add方法保存数据

_context.SaveChangesAsync():将更新的数据保存到数据库(持久化

代码说明:

(1)3个注解:

​ ◼ [HttpPost] 注解:表明只能由 POST 请求才能调用此 Action 方法,不写默认为[HttpGet] (第一个 Create 就是 GET )

​ ◼ [ValidateAntiForgeryToken] 注解:用于防止请求伪造 (更安全)

​ ◼ [Bind(“字段”)] 注解:指定能接收到的数据字段,防止过度发布 (更安全)

(2)return RedirectToAction( nameof(Index) );

​ ◼ **nemeof()**:获取变量或类型的名称,nameof(Index) :得到Index这个Action的名称,即字符串”Index”

​ ◼ 因此代码相当于:return RedirectToAction("Index"); 功能就是:重定向(跳转)到Index并执行


编辑操作 – Edit

有两个Edit操作:与Create操作类似

E_L_10

第一个Edit代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
public async Task<IActionResult> Edit( int? id )	// id参数
{
if (id == null || _context.Movie == null)
{
return NotFound();
}
var movie = await _context.Movie.FindAsync( id ); // ◼ FindAsync(id):根据id查找对象,没找到则返回null
if (movie == null)
{
return NotFound();
}
return View(movie);
}

Edit视图代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@model MvcMovie.Models.Movie
@{
ViewData["Title"] = "Edit";
}

<h1>Edit</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" /> <!-- id值的input是隐藏域(type="hidden") -->
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleaseDate" class="control-label"></label>
<input asp-for="ReleaseDate" class="form-control" />
<span asp-validation-for="ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

对比一下Create视图,可以看到二者代码几乎相同,但要注意:

(1) Edit 视图模板的 Model 对象一开始就接收了强类型传值

(2) Edit 视图必须要携带对象 Id 值(可隐藏不显示)才能实现最终的修改,否则提交无效


第二个Edit代码:(功能:将修改的数据提交保存到数据库)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit( int id, // id要单独接收
[Bind("Id,Title,ReleaseDate,Genre,Price")] Movie movie )
{
if ( id != movie.Id ) { return NotFound(); }
if ( ModelState.IsValid )
{
try
{
_context.Update(movie); // ◼ _context.Update():调用数据库上下文的Update方法更新数据
await _context.SaveChangesAsync();
}
catch ( DbUpdateConcurrencyException ) // 捕捉数据库更新异
{
if ( !MovieExists(movie.Id) )
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction( nameof(Index) );
}
return View( movie );
}

private bool MovieExists(int id)
{
return (_context.Movie?.Any(e => e.Id == id)).GetValueOrDefault(); // 含义:根据id查找对象,如果找到返回该对象,否则返回null
// Any(lambda表达式):判断满足表达式的对象是否存在
}

查询明细 – Details

E_L_11

Details界面:

E_L_12

Details代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public async Task<IActionResult> Details( int? id )
{
if (id == null || _context.Movie == null)
{
return NotFound();
}
var movie = await _context.Movie.FirstOrDefaultAsync( m => m.Id == id );
// ◼ FirstOrDefaultAsync(Lambda表达式):在集合中查找满足表达式的第一个元素,如果不存在,则返回null
if ( movie == null )
{
return NotFound();
}
return View(movie);
}

Details视图代码:和Index视图类似,只不过是单值

HtmlHelper类参考【附录2】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@model MvcMovie.Models.Movie
@{
ViewData["Title"] = "Details";
}

<h1>Details</h1>
<div>
<h4>Movie</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Title) <!-- @Html.DisplayNameFor用于显示属性的Display值(中文值) -->
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Title)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.ReleaseDate)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.ReleaseDate) <!-- @Html.DisplayFor用于显示属性的值 -->
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Genre)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Genre)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Price)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Price)
</dd>
</dl>
</div>
<div>
<a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
<a asp-action="Index">Back to List</a>
</div>

删除操作 – Delete

E_L_13

有两个Delete操作:

E_L_14

第一个Delete代码:(功能:根据id值查找对象,并送到Delete.cshtm视图显示)

1
2
3
4
5
6
7
8
9
10
11
12
13
public async Task<IActionResult> Delete ( int? id )	// 与Details代码一模一样
{
if (id == null || _context.Movie == null)
{
return NotFound();
}
var movie = await _context.Movie.FirstOrDefaultAsync(m => m.Id == id);
if (movie == null)
{
return NotFound();
}
return View(movie);
}

Delete视图代码:(前面与Details一样)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@model MvcMovie.Models.Movie
@{
ViewData["Title"] = "Delete";
}

<h1>Details</h1>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Movie</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Title)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.ReleaseDate)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.ReleaseDate)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Genre)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Genre)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Price)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Price)
</dd>
</dl>
<form asp-action="Delete">
<input type="hidden" asp-for="Id" />
<input type="submit" value="Delete" class="btn btn-danger" /> |
<a asp-action="Index">Back to List</a>
</form>
</div>

第二个Delete代码:(功能:根据id值查找Movie对象并删除)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed( int id )
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movie = await _context.Movie.FindAsync( id ); // ◼ FindAsync(id):根据id查找对象,没找到则返回null
if (movie != null)
{
_context.Movie.Remove(movie); // ◼ Remove():移除集合中的对象
}
await _context.SaveChangesAsync(); // 将更新保存到数据库(持久化)
return RedirectToAction(nameof(Index));
}

附录

【附录1】Tag Helpers技术

◼ Tag Helpers 允许服务器端在视图中动态创建和生成HTML元素属性

◼ 示例:

Tag Helpers写法

1
<a asp-controller="Movies" asp-action="Edit" asp-route-id="@item.ID">Edit</a>

生成的HTML(假设id=1)↓

1
<a href="/Movies/Edit/1">Edit</a>

一些常用的 asp-* 属性

属性 说明
asp-controller controller的名称
asp-action action方法的名称
asp-route-id id值
asp-for 为元素绑定模型属性
asp-validation-for 为元素添加验证消息

TagHelpers技术参考:

https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/tag-helpers/built-in/anchor-tag-helper?view=aspnetcore-5.0

https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-5.0

asp-for 示例:

Tag Helpers写法

1
<input asp-for="Title" class="form-control" />	<!-- 这个"Title"是模型的一个字段属性 -->

◼ 自动生成 id 和 name(默认都为模型属性名)

◼ 自动生成 type 类型(如string字段对应type=”text”)

◼ 自动绑定 value 值(模型字段如果有值)

原生写法

1
<input class="form-control" type="text" id="Title" name="Title" value="Title属性值">

asp-validation-for 示例

Tag Helpers写法

1
<span asp-validation-for="Email"></span>	<!-- 这个"Email"是模型的一个字段属性 -->

[Required]

[EmailAddress]

public string Email { get; set; }

◼ 添加 HTML5 的 data-valmsg-for="property" 属性

◼ 该元素会附加指定模型属性的输入字段中的验证错误消息

原生写法

1
2
3
<span class="field-validation-valid" data-valmsg-for="Email" data-valmsg-replace="true">
The Email Address field is required.
</span>

【附录2】Html Helper类

◼ HtmlHelper类:用于动态创建HTML标签或字符串,提供了很多返回HTML标签的方法

◼ 示例:

Html Helper写法

1
@Html.TextBoxFor(m => m.Name)

◼ 自动生成 input 标签,并根据模型属性确定type类型

◼ 自动生成 id 和 name(默认都为模型属性名)

◼ 自动绑定 value 值(模型字段如果有值)

生成的HTML

1
<input id="Name" name="Name" type="text" value="">

HtmlHelper类常用方法

方法 说明
DisplayNameFor 返回字段的Display值(如中文值,没有设置则默认为字段名)
DisplayFor 返回字段的值(字符串)
LabelFor 生成Label标签
TextBoxFor 生成input标签
ValidationMessageFor 生成span标签,用于验证消息

HtmlHelper类参考:

https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.mvc.viewfeatures.htmlhelper?view=aspnetcore-5.0


HtmlHelper类示例:(以Movie对象为例)

1
2
3
4
@Html.DisplayNameFor(m => m.Name)
@Html.DisplayFor(m => m.Name)
@Html.LabelFor(m => m.Name)
@Html.ValidationMessageFor(m => m.Name)

生成的HTML

1
2
3
4
电影名称 (属性的Display值)
肖申克的救赎 (属性值)
<label for="Name">Name</label>
<span class="field-validation-valid" data-valmsg-for="Name" data-valmsgreplace="true"></span>
 Comments
Comment plugin failed to load
Loading comment plugin
Powered by Hexo & Theme Keep
Unique Visitor Page View