ASP.NET Core Razor Pages 中 新增表单功能
admin
2022-03-04ASP.NET Core Razor Pages 中 新增表单功能
导航:
在此视频中,我们将讨论如何实现 Razor Pages,以帮助我们创建新学生。
在本系列的先前视频中,我们已经实现了 Edit Razor Pages。实现“创建” Razor Pages所需的 HTML 标记和代码与“编辑” Razor Pages非常相似。
与其创建单独的 Create Razor Pages并复制 HTML 和代码,我们不如在 Edit Razor Pages中修改代码,以便将其用于两个工作流程,所以我们接下来做的
- 新增学生
- 编辑现有学生
IStudentRepository.cs
包括 Add()方法以添加新学生
public interface IStudentRepository
{
IEnumerable<Student> GetAllStudents();
Student GetStudent(int id);
Student Update(Student updatedStudent);
Student Add(Student newStudent);
}
MockStudentRepository.cs
提供 Add()方法的实现。目前,我们仍在处理内存数据。因此,我们必须手动计算要添加的新学生的 ID 值。
public Student Add(Student newStudent)
{
newStudent.Id= _studentList.Max(s => s.Id) + 1;
_studentList.Add(newStudent);
return newStudent;
}
等后面添加对 SQL Server 的支持时,我们不必手动计算学生 ID 值。当插入新记录时,这将由 SQL Server 自动提供。我们将在即将到来的视频中看到这一点。
_Lyout.cshtml
布局
导航菜单位于“布局”视图中。在“添加”菜单项中包括以下 HTML。
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Students/Edit">添加</a>
</li>
Edit.cshtml
@*当添加一个新学生时,我们不会传递任何ID值。因此,使id路由参数可选。*@
@page "{id:min(1)?}/{handler?}"
@model EditModel
@{
var pageHeader = Model.Student.Id > 0 ? "编辑学生" : "添加学生";
ViewData["Title"] = pageHeader;
// 如果学生没有照片信息,就默认给他一张空照片
var photoPath = "~/images/" + (Model.Student.PhotoPath ?? "noimage.png");
}
<div class="row">
<div class="col-md-12">
<h1>消息通知配置开关</h1>
<form method="post" asp-page-handler="UpdateNotificationPreferences">
<div class="form-check">
<input asp-for="Notify" class="form-check-input" />
<label asp-for="Notify" class="form-check-label">
允许接收消息通知信息
</label>
</div>
<button type="submit" class="btn btn-primary">更新消息通知</button>
</form>
<hr />
</div>
<div class="col-md-12">
@*页面状态内容控制*@
<h1>@pageHeader</h1>
<form method="post" class="mt-3">
@*使用隐藏的input标签来存储提交表单时需要的学生id*@
<input hidden asp-for="Student.Id" />
<input hidden asp-for="Student.PhotoPath" />
<div asp-validation-summary="All" class="text-danger"></div>
@*asp-for TagHelper 负责在处理在不同的标签中显示现有的数据*@
<div class="form-group row">
<label asp-for="Student.Name" class="col-sm-2 col-form-label"> </label>
<div class="col-sm-10">
<input
asp-for="Student.Name"
class="form-control"
placeholder="Name"
/>
<span asp-validation-for="Student.Name" class="text-danger"></span>
</div>
</div>
<div class="form-group row">
<label asp-for="Student.Email" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input
asp-for="Student.Email"
class="form-control"
placeholder="Email"
/>
<span asp-validation-for="Student.Email" class="text-danger"></span>
</div>
</div>
<div class="form-group row">
<label
asp-for="Student.Major"
class="col-sm-2 col-form-label"
></label>
<div class="col-sm-10">
<select
asp-for="Student.Major"
class="custom-select mr-sm-2"
asp-items="Html.GetEnumSelectList<MajorEnum>()"
>
<option value="">请选择</option>
</select>
</div>
</div>
<div class="form-group row">
<label asp-for="Photo" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<div class="custom-file">
@*Photo属性类型是IFormFile,ASP. NET
Core会根据这个属性自动创建一个FileUpload控件 *@ @*
有关更具体的信息在《深入浅出ASP.NET Core》那本书有介绍 *@
<input asp-for="Photo" class="custom-file-input form-control" />
<label class="custom-file-label">更换图片</label>
</div>
</div>
</div>
@*显示有照片的学生信息*@
<div class="form-group row col-sm-4 offset-4">
<img
class="imageThumbnail"
src="@photoPath"
asp-append-version="true"
/>
</div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary">更新</button>
<a asp-page="/Students/Index" class="btn btn-primary">取消</a>
</div>
</div>
@section Scripts {
<script>
$(document).ready(function () {
$(".custom-file-input").on("change", function () {
var fileName = $(this).val().split("\\").pop();
$(this).next(".custom-file-label").html(fileName);
});
});
</script>
}
</form>
</div>
</div>
Edit.cshtml.cs
public class EditModel : PageModel
{
private readonly IStudentRepository studentRepository;
private readonly IWebHostEnvironment webHostEnvironment;
public EditModel(IStudentRepository studentRepository,
IWebHostEnvironment webHostEnvironment)
{
this.studentRepository = studentRepository;
//使用 IWebHostEnvironment 服务,我们可以获取wwwroot文件夹下的路径地址信息
this.webHostEnvironment = webHostEnvironment;
}
//这是显示模板将用于的属性,显示现有的学生数据
[BindProperty]
public Student Student { get; set; }
// 我们使用这个属性来存储和处理新上传的照片
[BindProperty]
public IFormFile Photo { get; set; }
[BindProperty]
public bool Notify { get; set; }
public string Message { get; set; }
/// <summary>
/// 设置id为可选参数
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public IActionResult OnGet(int? id)
{
//如果id参数有值,查询现有值学生详细信息,否则创建一个新学生
if (id.HasValue)
{
Student = studentRepository.GetStudent(id.Value);
}
else
{
Student = new Student();
}
if (Student == null)
{
return RedirectToPage("/NotFound");
}
return Page();
}
public IActionResult OnPost()
{
if (ModelState.IsValid)
{
if (Photo != null)
{
//上传新照片的时候,需要检查当前学生是否有已经存在的照片,如果有的话,就需要删除它,再上传新照片。
if (Student.PhotoPath != null)
{
string filePath = Path.Combine(webHostEnvironment.WebRootPath,
"images", Student.PhotoPath);
System.IO.File.Delete(filePath);
}
// 将新照片保存到wwwroot/images文件夹中,并更新student 的PhotoPath属性
Student.PhotoPath = ProcessUploadedFile();
}
//如果学生ID为> 0,则调用Update()来更新现有学生的详细信息,否则调用Add()来添加新学生
if (Student.Id > 0)
{
Student = _studentRepository.Update(Student);
}
else
{
Student = _studentRepository.Add(Student);
}
return RedirectToPage("Index");
}
return Page();
}
public IActionResult OnPostUpdateNotificationPreferences(int id)
{
if (Notify)
{
Message = "您已经打开了消息通知功能";
}
else
{
Message = "你已经关闭了消息通知功能";
}
//将确认消息存储在TempData中
TempData["message"] = Message;
// 将请求重定向到Details Razor Pages,并传递StudentId和Message。
//StudentId作为路由参数传递 , 将Message作为查询字符串传递
return RedirectToPage("Details", new { id = id });
}
/// <summary>
/// 处理文件上传
/// </summary>
/// <returns></returns>
private string ProcessUploadedFile()
{
string uniqueFileName = null;
if (Photo != null)
{
string uploadsFolder = Path.Combine(webHostEnvironment.WebRootPath, "images");
uniqueFileName = Guid.NewGuid().ToString() + "_" + Photo.FileName;
string filePath = Path.Combine(uploadsFolder, uniqueFileName);
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
Photo.CopyTo(fileStream);
}
}
return uniqueFileName;
}
}
ASP.NET Core 中的下拉列表验证
使班级下拉列表为必填字段
Student.cs
使用[Required]属性装饰 Student 类中的 Major 属性。
public class Student
{
public int Id { get; set; }
[Required(ErrorMessage = "请输入名字"), MaxLength(50, ErrorMessage = "名字的长度不能超过50个字符")]
[Display(Name = "名字")]
public string Name { get; set; }
[Required]
[Display(Name = "专业信息")]
public MajorEnum? Major { get; set; }
[Display(Name = "电子邮件")]
[RegularExpression(@"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$",
ErrorMessage = "邮箱的格式不正确")]
[Required(ErrorMessage = "请输入邮箱地址")]
public string Email { get; set; }
public string PhotoPath { get; set; }
Edit.cshtml
在 Major 下拉列表的下方包括 asp-validation-for
标签助手。
<div class="form-group row">
<label asp-for="Student.Major" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<select
asp-for="Student.Major"
class="custom-select mr-sm-2"
asp-items="Html.GetEnumSelectList<MajorEnum>()"
>
<option value="">请选择</option>
</select>
<span asp-validation-for="Student.Major" class="text-danger"></span>
</div>
</div>