Search code examples
asp.net-mvc-3modelstatemodel-validation

Required ModelValidation just for new objects ASP.NET MVC


I have this issue since yesterday. In my User model I have a [NotMapped] called "ConfirmPassword". I don´t save it on the database but I use it on my Create form as a always to validate the data input for new users.

Since than, it´s ok. The problem is on my [HttpPost] Edit action. I should be able to edit some user's data without type and confirm the password. I use both Password and ConfirmPassword as a way to confirm the old password and informe the new one, if I wanna change the password. But, if I don´t, I leave them blank.

I have used already the code below to be able to pass the ModelState.IsValid() condition and it worked:

ModelState["Password"].Errors.Clear();
ModelState["ConfirmPassword"].Errors.Clear();

But, just before the db.SaveChanges(), as User user view model is considered, it has both properties empty and I got:

Property: ConfirmPassword Error: The field ConfirmPassword is invalid.

The question is: How could I skip de Required model validation when I want to update an object?

I read already about custom ModelValidations with classes extending ValidationAttribute and DataAnnotationsModelValidator but I am not doing it right.

Any idea? How could I create a custom model validation that checks if the UserId property is null or not. It´s a nice way to check if I'm in Create or Edit action.

Thanks, Paulo


Solution

  • Using the domain objects as your ViewModel will leads you to a condition of less scalability. I would opt for seperate ViewModels specific for the Views. When i have to save the data i map the ViewModel to the Domain model and save that. In your speciific case, i would create 2 ViewModels

    public class CustomerViewModel
    {
      public string FirstName { set;get;}
      public string LastName { set;get;}
    }
    

    And i will Have another ViewModel which inherits from the above class, for the Create View

    public class CustomerCreateViewModel :CustomerViewModel
    {
       [Required]
       public string Password { set;get;}
    
       [Required]
       public string ConfirmPassword { set;get;}
    }
    

    Now in my Get actions, i use this ViewModel

    public ActionResult Create()
    {
      var vm=new CustomerCreateViewModel();
      return View(vm);
    }
    

    and of course my View(create.cshtml) is now binded to this ViewModel

    @model CustomerCreateViewModel
    <h2>Create Csustomer</h2/>
    //Other form stuff
    

    Similarly for My Edit Action,

    public ActionResult Edit(int id)
    {
      var vm=new CustomerViewModel();
      var domainCustomer=repo.GetCustomerFromID(id);
      if(domainCustomer!=null)
      {
          //This manual mapping can be replaced by AutoMapper.
          vm.FirstName=domainCustomer.FirstName;
          vm.LastName=domainCustomer.LastName;
      }
      return View(vm);
    }
    

    This view is bounded to CustomerViewModel

    @model CustomerViewModel
    <h2>Edit Info of @Model.FirstName</h2>
    //Other form stuff
    

    In your POST Actions, Map it back to the Domain object and Save

    [HttpPost]
    public ActionResult Create(CustomerCreateViewModel model)
    {
      if(ModelState.IsValid)
      {
          var domainCust=new Customer();
          domainCust.FirstName=model.FirstName;
          repo.InsertCustomer(domainCust);
          //Redirect if success (to follow PRG pattern)
      }
      return View(model);
    } 
    

    Instead of writing the Mapping yourself, you may consider using AutoMapper library to do it for you.