Manually invoking ModelState validation
Asked Answered
M

5

65

I'm using ASP.NET MVC 3 code-first and I have added validation data annotations to my models. Here's an example model:

public class Product
{
    public int ProductId { get; set; }

    [Required(ErrorMessage = "Please enter a name")]
    public string Name { get; set; }

    [Required(ErrorMessage = "Please enter a description")]
    [DataType(DataType.MultilineText)]
    public string Description { get; set; }

    [Required(ErrorMessage = "Please provide a logo")]
    public string Logo { get; set; }
}

In my website I have a multi-step process to create a new product - step 1 you enter product details, step 2 other information etc. Between each step I'm storing each object (i.e. a Product object) in the Session, so the user can go back to that stage of the process and amend the data they entered.

On each screen I have client-side validation working with the new jQuery validation fine.

The final stage is a confirm screen after which the product gets created in the database. However because the user can jump between stages, I need to validate the objects (Product and some others) to check that they have completed the data correctly.

Is there any way to programatically call the ModelState validation on an object that has data annotations? I don't want to have to go through each property on the object and do manual validation.

I'm open to suggestions of how to improve this process if it makes it easier to use the model validation features of ASP.NET MVC 3.

Ministerial answered 15/6, 2011 at 15:18 Comment(0)
P
75

You can call the ValidateModel method within a Controller action (documentation here).

Photofluorography answered 15/6, 2011 at 15:42 Comment(1)
Thanks, I used TryUpdateModel() in the end so I didn't have exceptions raised.Ministerial
E
52

ValidateModel and TryValidateModel

You can use ValidateModel or TryValidateModel in controller scope.

When a model is being validated, all validators for all properties are run if at least one form input is bound to a model property. The ValidateModel is like the method TryValidateModel except that the TryValidateModel method does not throw an InvalidOperationException exception if the model validation fails.

ValidateModel - throws exception if model is not valid.

TryValidateModel - returns bool value indicating if model is valid.

class ValueController : Controller
{
    public IActionResult Post(MyModel model)
    {
        if (!TryValidateModel(model))
        {
            // Do something
        }

        return Ok();
    }
}

Validate Models one-by-one

If you validate a list of models one by one, you would want to reset ModelState for each iteration by calling ModelState.Clear().

Link to the documentation

Emporium answered 15/11, 2013 at 7:21 Comment(3)
I have a Required field that is null and used "ModelState.Clear()" and the ModelState.IsValid is true.Ascensive
It works when I put "ModelState.Clear();" and "TryValidateModel(myModel);". ThanksAscensive
This may seem obvious after you think about it, but your custom Validate method will not be called if there are any validation errors within the validation attributes.Waggery
I
3
            //
            var context = new ValidationContext(model);

            //If you want to remove some items before validating
            //if (context.Items != null && context.Items.Any())
            //{
            //    context.Items.Remove(context.Items.Where(x => x.Key.ToString() == "Longitude").FirstOrDefault());
            //    context.Items.Remove(context.Items.Where(x => x.Key.ToString() == "Latitude").FirstOrDefault());
            //}

            List<ValidationResult> validationResults = new List<ValidationResult>();
            bool isValid = Validator.TryValidateObject(model, context, validationResults, true);
            if (!isValid)
            {
                //List of errors 
                //validationResults.Select(r => r.ErrorMessage)
                //return or do something
            }
Interspace answered 2/8, 2020 at 11:17 Comment(0)
C
2

I found this to work and do precisely as expected.. showing the ValidationSummary for a freshly retrieved object on a GET action method... prior to any POST

Me.TryValidateModel(MyCompany.OrderModel)
Cadman answered 6/9, 2013 at 18:50 Comment(0)
T
0

In Dot net core you can use TryValidateModel. Before calling it, you need to reset your modelState.

    //you may need to put any logical change on model
    model.IsDefault = model.IsDefault??false;//I was having IsDefault as empty string
    //clear the model state
    ModelState.Clear();
    
    if(TryValidateModel(model)){
        //your code
    }else{
        //handle the invalid model
    }

Or you can remove the field which you don't want to put in validation with

ModelState.Remove("FieldName");

The FieldName can the name of the key in the model or if the field is a class object's property then field name will be like bellow

ModelState.Remove("ClassName.FieldName");

In DotNet MVC, you can use

ModelState.Clear();
Validate(entity);
//or remove the field 
ModelState.Remove("FieldName");
if (ModelState.IsValid) {
        //your code
}else{
        //handle the invalid model
}
Tizzy answered 5/1 at 5:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.