Search code examples
c#asp.net-corevalidationasp.net-core-mvc

Validation error in ASP.NET Core - the field is required


I have a project that I am studying, it consists of a small ASP.NET Core MVC app.

I followed the course, however, the version used in the videos is 2.1 and I have 5,6,7.

The error consists of ModelState.IsValid. The problem is that my create.cshtml form is requiring a field that I don't have in the form. I have a DepartmentId field but it asks for Department.

My classes and the error:

Seller.cs:

using System.ComponentModel.DataAnnotations;

namespace LojaWebMvc.Models;

public class Seller
{
    public int Id { get; set; }
    [Required(ErrorMessage ="{0} required")]
    [StringLength(60, MinimumLength = 3, ErrorMessage ="{0} size shold be between {2} and {1}")]
    public string Name { get; set; }

    [Required(ErrorMessage ="{0} required")]
    [EmailAddress(ErrorMessage = "Enter a valid email")]
    public string Email { get; set; }

    [Display(Name="Birth Date")]
    [DataType(DataType.Date)]
    [Required(ErrorMessage ="{0} required")]
    public DateTime BirthDate { get; set; }
 
    [Display(Name = "Base Salary")]
    [DisplayFormat(DataFormatString ="{0:F2}")]
    [Required(ErrorMessage ="{0} required")]
    [Range(100.0, 5000.0, ErrorMessage ="{0} must be from {1} to {2}")]
    public double BaseSalary { get; set; }

    public Department Department {get; set;}
    public int DepartmentId { get; set; }

    public ICollection<SalesRecord> Sales {get; set;} = new List<SalesRecord>();

    public Seller()
    {
    }

    public Seller(int id, string name, string email, DateTime birthdate, double salary, Department department)
    {
        Id = id;
        Name = name;
        Email = email;
        BirthDate = birthdate;
        BaseSalary = salary;
        Department = department;
    }

    public void AddSales(SalesRecord sr)
    {
        Sales.Add(sr);
    }

    public void RemoveSales(SalesRecord sr)
    {
        Sales.Remove(sr);
    }

    public double TotalSales(DateTime initial, DateTime final)
    {
        return Sales.Where(sr => sr.Date >= initial && sr.Date <= final).Sum(sr => sr.Amount);
    }
}

Department.cs:

namespace LojaWebMvc.Models;

public class Department
{
    public int Id { get; set; }
    public string Name { get; set; }

    public ICollection<Seller> Sellers { get; set; } = new List<Seller>();

    public Department()
    {
    }

    public Department(int id, string name)
    {
        Id = id;
        Name = name;
    }

    public void AddSeller(Seller seller)
    {
        Sellers.Add(seller);
    }

    public double TotalSales(DateTime initial, DateTime final)
    {
        return Sellers.Sum(seller => seller.TotalSales(initial, final));
    }
}

DepartmentService FindAll:

...
public List<Department> FindAll()
{
    //return _vsproContext.Department.OrderBy(x => x.Name).ToList();
    var list = _vsproContext.Department;
    var obj = new List<Department>();

    obj = list.Select(x => new Department(
        x.Id,
        x.Name  
    )).ToList();

    return obj;
}
...

SellerService:

using LojaWebMvc.Models;
using LojaWebMvc.Services.Interfaces;
using LojaWebMvc.Data;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using LojaWebMvc.Services.Exceptions;

namespace LojaWebMvc.Services;

public class SellerService: ISellerService
{
    private readonly VsproContext _vsproContext;

    public SellerService(VsproContext vsproContext)
    {
        _vsproContext = vsproContext;
    }

    //

    public List<Seller> FindAll()
    {
        // return _vsproContext.Seller.OrderBy(x => x.Name).ToList();
        var list = _vsproContext.Seller;
        var obj = list.Select(x => new Seller(x.Id, x.Name,
                x.Email, x.BirthDate, x.BaseSalary, x.Department)).ToList();
        return obj;
    }

    public Seller FindById(int id)
    {
        return _vsproContext.Seller.Include(obj => obj.Department).FirstOrDefault(x => x.Id == id);
        // var obj = _vsproContext.Seller.Find(id);
        // return obj;
    }

    public Seller Insert(Seller seller)
    {
        _vsproContext.Add(seller);
        _vsproContext.SaveChanges();
        return seller;
    }

    public void Remove(int id)
    {
        var obj = _vsproContext.Seller.Find(id);
        _vsproContext.Remove(obj);
        _vsproContext.SaveChanges();
    }

    public void Update(Seller seller)
    {
        if (!_vsproContext.Seller.Any(x => x.Id == seller.Id))
        {
            throw new NotFoundException("Error - Id not found");
        }

        try
        {
            _vsproContext.Update(seller);
            _vsproContext.SaveChanges();
         }
         catch(DbUpdateConcurrencyException e) 
         {
             throw new DbConcurrencyException(e.Message);
         }
    }
}

Controller:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Seller seller)
{
    if (!ModelState.IsValid)
    {
        var message = string.Join(" | ", ModelState.Values
                            .SelectMany(v => v.Errors)
                            .Select(e => e.ErrorMessage));
        System.Console.WriteLine(ModelState.Values);

        var departments = _departmentService.FindAll();
        var viewModel = new SellerFormViewModel{ Seller = seller, Departments = departments};
        System.Console.WriteLine(message);

        return View("Create", viewModel);
    }
         
    _sellerService.Insert(seller);
    return RedirectToAction("Index");
}

If you remove the if(!ModelState.Isvalid)... it works normally, but if I try to validate, it doesn't save it in the database and doesn't return any error. I am stuck. I got the error output using

System.Console.WriteLine(message)

Error:

The Department field is required.


Solution

  • you can try to add ? manully to like:

    public Department? Department {get; set;}
    

    or: you can remove <Nullable>enable</Nullable> from your project file (double-click the project name or right-click the project to choose Edit Project File). You can read this to know more.