I am building a C# assignment and facing an issue. I have 2 models students
and course
. I needed a place to show all the students related to a course and ability to add new student. So I created a new view model CourseViewModel
:
using ProblemAssignment2.Models;
namespace ProblemAssignment2.ViewModels
{
public class CourseViewModel
{
public Course Course { get; set; }
public Student NewStudent { get; set; }
}
}
I have a Manage.cshtml
page in views/Course
folder.
@model ProblemAssignment2.ViewModels.CourseViewModel
<h1>Manage Course</h1>
<div>
<h4>@Model.Course.Title</h4>
<table class="table">
<thead>
<tr>
<th>Last Name</th>
<th>First Name</th>
<th>Email</th>
<th>Status</th>
</tr>
</thead>
<tbody>
@foreach (var student in Model.Course.Students)
{
<tr>
<td>@student.LastName</td>
<td>@student.FirstName</td>
<td>@student.Email</td>
<td>@student.EnrollmentStatus</td>
</tr>
}
</tbody>
</table>
</div>
<h2>Create Student</h2>
<form asp-action="createStudent" method="post">
<div class="form-group">
<label asp-for="NewStudent.LastName" class="control-label">Last Name</label>
<input asp-for="NewStudent.LastName" name="Last" class="form-control" />
<span asp-validation-for="NewStudent.LastName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="NewStudent.FirstName" class="control-label">First Name</label>
<input asp-for="NewStudent.FirstName" name="First" class="form-control" />
<span asp-validation-for="NewStudent.FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="NewStudent.Email" class="control-label">Email</label>
<input asp-for="NewStudent.Email" name="Email" class="form-control" />
<span asp-validation-for="NewStudent.Email" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Create Student</button>
</form>
<h2>Send Confirmation Message</h2>
<form asp-action="SendConfirmationMessage" method="post">
<input type="hidden" name="courseId" asp-for="@Model.Course.CourseID" />
<button type="submit" class="btn btn-secondary">Send Confirmation Message</button>
</form>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
In CourseController
, I have added 2 methods to show view and create student:
public async Task<IActionResult> Manage(int? id)
{
if (id == null)
{
return NotFound();
}
var course = await _context.Courses
.Include(c => c.Students)
.FirstOrDefaultAsync(m => m.CourseID == id);
if (course == null)
{
return NotFound();
}
var viewModel = new CourseViewModel
{
Course = course,
NewStudent = new Student()
};
return View(viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> createStudent(int id, CourseViewModel viewModel)
{
Debug.WriteLine(viewModel.Course.CourseID);
viewModel.NewStudent.EnrollmentStatus = Student.Status.InvitationSent;
if (ModelState.IsValid)
{
var course = await _context.Courses.FindAsync(id);
if (course == null)
{
return NotFound();
}
viewModel.NewStudent.CourseID = id;
viewModel.NewStudent.EnrollmentStatus = Student.Status.InvitationSent; // Default status
_context.Students.Add(viewModel.NewStudent);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Manage), new { id = viewModel.Course.CourseID });
}
// If ModelState is invalid, return the Manage view with the current viewModel
return View(nameof(Manage), id);
}
I am able to view all the students related to course. But when I add some data to form and try to submit it, I get null exceptions.
I added breakpoints on createstudent
and found out that id value is 0 and viewModel.Course
and viewModel.NewStudent
both are null. What can be reason that on submit of form both these values are getting set to null?
I have checked in manage function I am setting course value and also initializing newStudent to a object.
Thanks everyone for your help. I started working on the solution provided by @yong-shun and made a few more changes to the form.
<form asp-action="createStudent" method="post" asp-route-id="@Model.Course.CourseID">
<div class="form-group">
<label asp-for="@Model.NewStudent.LastName" class="control-label">Last Name</label>
<input asp-for="@Model.NewStudent.LastName" name="NewStudent.LastName" class="form-control" />
<span asp-validation-for="NewStudent.LastName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.NewStudent.FirstName" class="control-label">First Name</label>
<input asp-for="@Model.NewStudent.FirstName" name="NewStudent.FirstName" class="form-control" />
<span asp-validation-for="NewStudent.FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.NewStudent.Email" class="control-label">Email</label>
<input asp-for="@Model.NewStudent.Email" name="NewStudent.Email" class="form-control" />
<span asp-validation-for="NewStudent.Email" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Create Student</button>
</form>
I changed asp-for="NewStudent.Email" to asp-for="@Model.NewStudent.Email". SO adding @Model in all the fields made submitted form passed with model values.