ASP.NET Core Razor Pages 中 新增表单功能

admin
admin
2022-03-04
分享:

ASP.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>