2

This is an example on dotnet. github.com/dotnet... I work it on version net-6.0

The result of the validation check is false because the navigational properties of the class participate in the validation. I implemented a simple experiment on net-5.0 - navigational properties are not reflected in the result. But, maybe I'm wrong.

How to solve this problem correctly?

public class Course
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    [Display(Name = "Number")]
    public int CourseID { get; set; }

    [StringLength(50, MinimumLength = 3)]
    public string Title { get; set; }

    [Range(0, 5)]
    public int Credits { get; set; }

    public int DepartmentID { get; set; }

    public Department Department { get; set; }
    public ICollection<Enrollment> Enrollments { get; set; }
    public ICollection<CourseAssignment> CourseAssignments { get; set; }
}

CoursesController.cs

// POST: Courses/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
    [Bind("CourseID,Credits,DepartmentID,Title")] Course course)
{
    if (ModelState.IsValid)
    {
        _context.Add(course);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    PopulateDepartmentsDropDownList(course.DepartmentID);
    return View(course);
}

Validation result

Validation result

Yong Shun
  • 35,286
  • 4
  • 24
  • 46
dtk77
  • 75
  • 6
  • Hi, since you label the question as .net-6.0, I updated the tags to `asp.net-core`,`asp.net-core-mvc` which are more suitable. – Yong Shun Feb 03 '22 at 09:40

2 Answers2

4

I think the problem is a new nullable feature net6. I highly recommend you to remove it or comment in project properties

 <!--<Nullable>enable</Nullable>-->

It is a very stupid feature. You will have to mark all properties as nullable till the end of your life.

public ICollection<CourseAssignment>? CourseAssignments { get; set; }

and IMHO never use bind in the controller action parameters. You will always have problems with it. It is only usefull in razor pages, but in very very rare cases. And use Dto in a very rare casess. I usually use Dto only for select when I have to create the most properties from joins.

Serge
  • 40,935
  • 4
  • 18
  • 45
0

Not sure this answers your question or not. But would suggest you create a Data Transfer Object (DTO) class rather than directly use the (generated) Database object class.

The DTO class is designed based on what value (schema) API is expected to receive. And this DTO class would also be used for doing the first-level data validation such as Required, Range and etc. (without involving validation against database)

public class CreateCourseDto
{
    [Display(Name = "Number")]
    public int CourseID { get; set; }

    [StringLength(50, MinimumLength = 3)]
    public string Title { get; set; }

    [Range(0, 5)]
    public int Credits { get; set; }

    public int DepartmentID { get; set; }
}

Then only bind the value from DTO to the real DB object. Either manually bind/assign the value or apply tool/library such as AutoMapper.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
    [Bind("CourseID,Credits,DepartmentID,Title")] CreateCourseDto course)
{
    if (ModelState.IsValid)
    {
        // Map received course value to DB object 
        Course _course = new Course
        {
            CourseID = course.CourseID,
            Title = course.Title,
            Credits = course.Credits, 
            DepartmentID = course.DepartmentID
        };

        _context.Add(_course);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    PopulateDepartmentsDropDownList(course.DepartmentID);
    return View(course);
}
Yong Shun
  • 35,286
  • 4
  • 24
  • 46