How to separate business logic layer using ModelState wrapper class in .net core mvc

663 Views Asked by At

I am developing Web Applications using ASP.Net MVC 5 (.net framework), now trying develop my next Project using .NET Core 3.1 with Entity framework Core (with Code first approach).

I am trying separate business logic in a separate Wrapper class like:

public interface IValidationDictionary
{
    void AddError(string key, string errorMessage);
    bool IsValid { get; }
}

public class ModelStateWrapper : IValidationDictionary
{
    private ModelStateDictionary _modelState;

    public ModelStateWrapper(ModelStateDictionary modelState)
    {
        _modelState = modelState;
    }

    #region IValidationDictionary Members

    public void AddError(string key, string errorMessage)
    {
        _modelState.AddModelError(key, errorMessage);
    }

    public bool IsValid
    {
        get { return _modelState.IsValid; }
    }
    #endregion
}

In the EmployeeRepo class:

    private Models.IValidationDictionary _modelState;
    public EmployeeRepo(Models.IValidationDictionary modelState)
    {
        _modelState = modelState;
    }

   public int Create(Models.Employee ObjToCreate)
   {
        if (!Validate(ObjToCreate))
            return 0;

        _context.Employee.Add(ObjToCreate);
        _context.SaveChanges();

        return ObjToCreate.Id;
   }

    protected bool Validate(Models.Employee objToValidate)
    {
        if (objToValidate.Name.Trim().Length == 0)
            _modelState.AddError("Name", "Name is required.");

        if (null == objToValidate.DOB)
            _modelState.AddError("DOB", "DOB is required");
        return _modelState.IsValid;
    }

In the Controller:

private Repository.IEmployeeRepo repo;
public EmployeesController(ApplicationDbContext context)
{
    _context = context;
    repo = new Repository.EmployeeRepo(new Models.ModelStateWrapper(this.ModelState));
}

    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult Create([Bind("Name,DOB,Department")] Employee employee)
    {
        var respId = repo.Create(employee);
        if (0 != respId.Id)
        {
            return RedirectToAction(nameof(Details), new { id = respId.Id });
        }
        return View(employee);
    }

I am expecting ModelState errors to be update in the controller which is added by the wrapper class, but model validation error not updating in the Controller.

Thanks for your time and for any response.

With Best Regards, Raju Mukherjee

1

There are 1 best solutions below

4
LouraQ On

You just want to use a custom verification method to verify these two fields, right?

The method you wrote is too complicated.

To bind the corresponding error message, you need to add your custom verification attribute above the corresponding fields like [Required].

In fact, you only need to inherit the ValidationAttribute method and rewrite the IsValid method.

    public class Employee
    { 
        public int Id { get; set; }

        [CustomValidate]
        public string Name { get; set; }

        [CustomValidate]
        public string DOB { get; set; }

        public string Department{ get; set; }
    }

Custom Method:

 public class CustomValidateAttribute : ValidationAttribute
    {
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (value == null || string.IsNullOrEmpty(value.ToString().Trim()))
            {
                return new ValidationResult(validationContext.DisplayName + " is required.");
            }

            return ValidationResult.Success;
        }
    }

Create:

 [HttpPost]
        public IActionResult Create([Bind("Name,DOB,Department")]Employee employee)
        { 
            if (ModelState.IsValid)
            {
                _context.Employee.Add(employee); 
                _context.SaveChanges();
                return RedirectToAction(nameof(Details), new { id = employee.Id });
            }
            return View(employee);
        }

Here is the test result:

enter image description here