【问题标题】:C# Asp Core 2.2 Model Binding Object Instantiated in OnGet() But Not In OnPost()C# Asp Core 2.2 模型绑定对象在 OnGet() 中实例化但不在 OnPost() 中
【发布时间】:2020-04-03 22:46:09
【问题描述】:

所以我遇到了一个我希望结果是愚蠢的问题。我有以下课程 查看Students.cshtml.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using HogwartsRegistry.Data;
using HogwartsRegistry.Models;
using HogwartsRegistry.Models.ViewModels;
using HogwartsRegistry.Utility;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;

namespace HogwartsRegistry.Pages.Instructors
{
    public class ViewStudentsModel : PageModel
    {
        private readonly ApplicationDbContext _db;
        public ViewStudentsModel(ApplicationDbContext db)
        {
            _db = db;
        }


        [BindProperty]
        public InstructorViewStudentsViewModel InstrViewVM { get; set; }

        public void OnGet(int classId)
        {
            var ClaimsIdentity = (ClaimsIdentity)User.Identity;
            var claim = ClaimsIdentity.FindFirst(ClaimTypes.NameIdentifier);
            string instructorId = claim.Value;

            InstrViewVM = new InstructorViewStudentsViewModel()
            {
                Class = _db.Classes.FirstOrDefault(i => i.Id == classId),

            };

            // Get a list of people enrolled in the current class
            InstrViewVM.Students = _db.StudentClasses
                        .Include(s => s.Student)
                        .Include(s => s.Class.Course)
                        .Where(s => s.ClassId == classId)
                        .ToList();

            // Get the studentIds of everyone enrolled in the class
            List<string> studentIds = InstrViewVM.Students.Select(s => s.StudentId).ToList();

            InstrViewVM.otherStudents = _db.Students
                                        .Where(s => !studentIds.Contains(s.Id))
                                        .ToList();

            var count = InstrViewVM.otherStudents.Count;
            StringBuilder param = new StringBuilder();
            param.Append("/Students?studentPage=:");

            InstrViewVM.PagingInfo = new PagingInfo()
            {
                CurrentPage = 1,
                ItemsPerPage = SD.PaginationUserPageSize,
                TotalItems = count,
                UrlParameters = param.ToString()
            };

            InstrViewVM.otherStudents = InstrViewVM.otherStudents
                .OrderBy(u => u.LastName)
                .Skip((1 - 1) * SD.PaginationUserPageSize)
                .Take(InstrViewVM.PagingInfo.ItemsPerPage).ToList();

        }

        public void OnGetSearch(int studentPage = 1, string searchLastName = null, string searchYear = null, string searchHouse = null)
        {


            StringBuilder param = new StringBuilder();
            param.Append("/Students?studentPage=:");

            if (searchLastName != null)
            {
                param.Append("&searchLastName=");
                param.Append(searchLastName);
                InstrViewVM.otherStudents = InstrViewVM.otherStudents.Where(s => s.LastName == searchLastName).ToList();
            }

            if (searchYear != null)
            {
                param.Append("&searchYear=");
                param.Append(searchYear);
                InstrViewVM.otherStudents = InstrViewVM.otherStudents.Where(s => s.Year == Convert.ToInt32(searchYear)).ToList();
            }

            if (searchHouse != null)
            {
                param.Append("&searchHouse=");
                param.Append(searchHouse);
                InstrViewVM.otherStudents = InstrViewVM.otherStudents.Where(s => s.House == searchHouse).ToList();
            }


        }


        public async Task<IActionResult> OnPostUnenrollStudent(int studentClassId)
        {

            StudentClasses classEntry = await _db.StudentClasses.FindAsync(studentClassId);
            _db.StudentClasses.Remove(classEntry);
            await _db.SaveChangesAsync();
            return Page();
        }

        public async Task<IActionResult> OnPostEnroll(string studentId)
        {
            if (ModelState.IsValid)
            {
                StudentClasses enrollment = new StudentClasses();
                enrollment.StudentId = studentId;
                enrollment.ClassId = InstrViewVM.Class.Id;
                _db.StudentClasses.Add(enrollment);
                await _db.SaveChangesAsync();
            }
            return Page();
        }
    }
}

以及随附的 HTML:

@page
@model HogwartsRegistry.Pages.Instructors.ViewStudentsModel
@{
    ViewData["Title"] = "ViewStudents";
}
<div class="scratches">
    <h1>View Students</h1>
    @if (Model.InstrViewVM.Students.Count > 0)
    {
    <form method="post">
        <table class="table table-striped">
            <tr class="table table-secondary">
                <th>@Html.DisplayNameFor(s => Model.InstrViewVM.Students[0].Id)</th>
                <th>@Html.DisplayNameFor(s => Model.InstrViewVM.Students[0].Class.CRN)</th>
                <th>@Html.DisplayNameFor(s => Model.InstrViewVM.Students[0].Class.Course.CourseNum)</th>
                <th>@Html.DisplayNameFor(s => Model.InstrViewVM.Students[0].Class.Course.CourseTitle)</th>
                <th>@Html.DisplayNameFor(s => Model.InstrViewVM.Students[0].Student.FirstName)</th>
                <th>@Html.DisplayNameFor(s => Model.InstrViewVM.Students[0].Student.LastName)</th>
                <th></th>
            </tr>

            @foreach (var stud in Model.InstrViewVM.Students)
            {
                <tr>
                    <td>@Html.DisplayFor(s => stud.Id)</td>
                    <td>@Html.DisplayFor(s => stud.Class.CRN)</td>
                    <td>@Html.DisplayFor(s => stud.Class.Course.CourseNum)</td>
                    <td>@Html.DisplayFor(s => stud.Class.Course.CourseTitle)</td>
                    <td>@Html.DisplayFor(s => stud.Student.FirstName)</td>
                    <td>@Html.DisplayFor(s => stud.Student.LastName)</td>
                    <td><button type="submit" class="btn btn-danger small" asp-page-handler="UnenrollStudent" asp-route-studentClassId="@stud.Id">Delete</button></td>
                </tr>
            }
        </table>
    </form>
    }
</div>
<br />
<br />
<form method="get">
    <div class="scratches">
        <h3>Add a Student</h3>
        <div class="border">
            <div style="height: 60px;" class="container border border-secondary">
                <div class="row">
                    <div class="col-11">
                        <div class="row" style="padding-top:10px">
                            <div class="col-4">
                                @Html.Editor("searchLastName", new
                                {
                                    htmlAttributes = new
                                    {
                                @class = "form-control",
                                placeholder = "Last Name..."
                                }
                                }
                                )
                            </div>
                            <div class="col-4">
                                @Html.Editor("searchYear", new
                                {
                                    htmlAttributes = new
                                    {
                                @class = "form-control",
                                placeholder = "Year..."
                                }
                                }
                                )
                            </div>
                            <div class="col-4">
                                @Html.Editor("searchHouse", new
                                {
                                    htmlAttributes = new
                                    {
                                @class = "form-control",
                                placeholder = "House..."
                                }
                                }
                                )
                            </div>
                        </div>
                    </div>
                    <div class="col-1">
                        <div class="row" style="padding-top:10px; padding-right:15px;">
                            <button type="submit" name="submit" class="btn btn-info form-control" value="Search" asp-page-handler="Search"><i class="fas fa-search"></i></button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</form>

<form method="post">
    <div class="scratches">
    <table class="table table-striped">
        <tr class="table table-secondary">
            <th>@Html.DisplayNameFor(s => Model.InstrViewVM.otherStudents[0].FirstName)</th>
            <th>@Html.DisplayNameFor(s => Model.InstrViewVM.otherStudents[0].LastName)</th>
            <th>@Html.DisplayNameFor(s => Model.InstrViewVM.otherStudents[0].Year)</th>
            <th>@Html.DisplayNameFor(s => Model.InstrViewVM.otherStudents[0].House)</th>
            <th><!-- Empty for formatting--></th>
        </tr>
        @foreach (var stud in Model.InstrViewVM.otherStudents)
        {
            <tr>
                <td>@Html.DisplayFor(s => stud.FirstName)</td>
                <td>@Html.DisplayFor(s => stud.LastName)</td>
                <td>@Html.DisplayFor(s => stud.Year)</td>
                <td>@Html.DisplayFor(s => stud.House)</td>
                <td><button type="submit" class="btn btn-info" asp-page-handler="Enroll" 
                                                               asp-route-studentId="@stud.Id">
                    <i class="fa fa-plus"></i> Enroll</button></td>
            </tr>
        }
        <tr>
            <td colspan="5" class="text-right">
                <div page-model="@Model.InstrViewVM.PagingInfo" asp-action="Index" page-class="btn border"
                     page-class-normal="btn btn-light" page-class-selected="btn btn-info active" class="btn-group"></div>
            </td>
        </tr>
    </table>
    </div>
</form>

还有视图模型

using System.Collections.Generic;

namespace HogwartsRegistry.Models.ViewModels
{
    public class InstructorViewStudentsViewModel
    {
        public Class Class { get; set; }
        public List<StudentClasses> Students { get; set; }
        public List<Student> otherStudents { get; set; }
        public PagingInfo PagingInfo { get; set; }
    }
}

我遇到的问题是,当页面加载并调用 OnGet(int classId) 时,我绑定的 InstrViewVM 中的所有内容都会被填充

然而,如果我单击任何按钮取消注册 (OnPostUnenrollStudent) 或注册 (OnPostEnroll) 学生,我的 InstrViewVM 模型绑定对象突然没有实例化。当我尝试注册学生时,InstrViewVM 对象为空,如下所示

当我试图取消学生注册时,我收到了这个错误

当我在 OnGet(classId) 方法中明确实例化它时,我似乎无法弄清楚为什么我的模型绑定没有实例化。任何帮助,将不胜感激。如果我需要提供更多信息,请告诉我。

【问题讨论】:

    标签: c# asp.net-core razor-pages


    【解决方案1】:

    OnGet 方法仅在响应使用 get 动词的 HTTP 请求时执行。您的按钮点击会生成post 请求。在之前的 get 请求中生成的任何状态都不会保留(因为 HTTP 是无状态的),因此您还需要在 post 处理程序方法中重新生成模型等。

    将模型实例化重构为一个单独的方法,并在OnGetOnPost 方法中调用它可能是个好主意。

    【讨论】:

      【解决方案2】:

      原因是你使用了&lt;td&gt;@Html.DisplayFor(s =&gt; stud.FirstName)&lt;/td&gt;,它只是呈现像&lt;td&gt;FirstNameSample&lt;/td&gt; 这样的值,而没有name 属性。

      表单标签只发送标签元素inputselecttextarea、...具有name属性。因此,当您发布表单时,您的绑定失败并且不会向处理程序发送任何内容。您可以随时在浏览器中按F12 来检查“网络”选项卡以查看您已发送的表单数据。

      解决方案是您可以改用&lt;input asp-for=" "&gt;

      @{int i = 0;}
      @foreach (var stud in Model.InstrViewVM.Students)
              {
                  <tr>
                      <td><input asp-for="@Model.InstrViewVM.Students[@i].Id" /></td>
                      <td><input asp-for="@Model.InstrViewVM.Students[@i].Class.CRN" /></td>
                      <td><input asp-for="@Model.InstrViewVM.Students[@i].Class.Course.CourseNum" /></td>
                      <td><input asp-for="@Model.InstrViewVM.Students[@i].Class.Course.CourseTitle" /></td>
                      <td><input asp-for="@Model.InstrViewVM.Students[@i].Student.FirstName" /></td>
                      <td><input asp-for="@Model.InstrViewVM.Students[@i].Student.LastName" /></td>            
                      <td><button type="submit" class="btn btn-danger small" asp-page-handler="UnenrollStudent" asp-route-studentClassId="@stud.Id">Delete</button></td>
                  </tr>
      
                  i++;
              }
      

      或者你可以使用@Html.EditorFor 喜欢

      @Html.EditorFor(model => model.InstrViewVM.Students[@i].Id, new { htmlAttributes = new { @class = "form-control", Name = "InstrViewVM.Students[" + @i + "].Id", @id = "InstrViewVM.Students[" + @i + "].Id" } })
      

      【讨论】:

        猜你喜欢
        • 2019-09-09
        • 2020-07-07
        • 2019-10-03
        • 1970-01-01
        • 1970-01-01
        • 2021-05-23
        • 1970-01-01
        • 2019-11-11
        • 2020-10-08
        相关资源
        最近更新 更多