Partial server side validation for complex property

87 Views Asked by At

In ASP.NET Core MVC app, I need to skip model validation for certain complex property in controller's action.
Let's say I have a following model structure:

public class Person
{
    public int PersonID { get; set; }
    public PersonalInfo PersonalInfo { get; set; }
    public ContactInfo ContactInfo { get; set; }

    public Person()
    {
        PersonalInfo = new PersonalInfo();
        ContactInfo = new ContactInfo();
    }
}

public class PersonalInfo 
{
        [Required(ErrorMessage = "First name is required")]
        public string FirstName { get; set; }

        [Required(ErrorMessage = "Last name is required")]
        public string LastName { get; set; }
}

public class ContactInfo 
{
        [Required(ErrorMessage = "Phone is required")]
        public string Phone { get; set; }

        [Required(ErrorMessage = "Email is required")]
        public string Email{ get; set; }
}

In post action, I would like to skip validation for ContactInfo, although it is a part of model and is submitted. Something like this:

[HttpPost]
public ActionResult SavePerson(Person model)
{
    ModelState.Remove("ContactInfo");
    if (ModelState.IsValid)
    { 
        (...)
    }
}

This would work if ContactInfo was simple (is "scalar" correct term?) property.
I know that some of you would suggest me to use seperate viewmodels, but I do not think it is applicable in this case (I'm trying to create a form with multiple steps, and all the data has to be on form in order to be submitted in order to be preserved between steps...)
Also, I guess I could use ModelState.Remove for each property of ContactInfo class, but it seems repetitive and difficult to maintain, especially because my classes contain much more properties.

2

There are 2 best solutions below

2
On BEST ANSWER

ModelState.Remove("ContactInfo");

Seems that the ModelState doesn't contain the "ContactInfo" key, so it will not work. If you want to disable the validation in the child class, as you guess, you need to remove all properties in it, such as:

ModelState.Remove("ContactInfo.Phone");
ModelState.Remove("ContactInfo.Email");

but it seems repetitive and difficult to maintain, especially because my classes contain much more properties.

It is indeed repetitive when there are many properties, but you can use reflection to simplify it.

foreach (var property in model.ContactInfo.GetType().GetProperties())
{
    ModelState.Remove("ContactInfo." + property.Name);
}
2
On

If you have arrays try following. If you do not use XmlElement with an array Xml Serialization requires two Xml Tags. Using XmlElement requires only one tag. :

    [XmlElement()]
    public List<PersonalInfo> PersonalInfo { get; set; }
    [XmlElement()]
    public List<ContactInfo> ContactInfo { get; set; }