C#Asp Core 2.2模型绑定对象在OnGet()中实例化,但不在OnPost()中实例化

时间:2019-12-10 17:19:56

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

所以我遇到了一个问题,我希望这是一个愚蠢的问题。我有以下课程 ViewStudents.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>

还有ViewModel

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中的所有内容 InstrViewVM object values after OnGet(int classId) call

但是,如果我单击任意按钮以取消注册(OnPostUnenrollStudent)或注册(OnPostEnroll)学生,我的InstrViewVM模型绑定对象突然不会实例化。当我尝试招收学生时,InstrViewVM对象为null,如下所示 enter image description here

当尝试取消学生注册时,出现此错误 enter image description here

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

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

原因是您使用的<td>@Html.DisplayFor(s => stud.FirstName)</td>仅呈现了具有<td>FirstNameSample</td>属性的name之类的值。

form标记仅发送具有属性input的标记元素selecttextareaname,...。因此,当您发布表单时,您的绑定将失败并且不向处理程序发送任何内容。您始终可以在浏览器中按F12来检查“网络”选项卡以查看您发送的表单数据。

解决方案是您可以改用<input asp-for=" ">

@{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" } })