Mvc: Web Api Validation of input parameter. Modelstate.IsValid always true.

Created on 27 Jan 2017  路  9Comments  路  Source: aspnet/Mvc

I have an Mvc core web api with a simple Post method.

Case Model:

public class Case {
        [Required]
        public string CaseReference { get; set; }

        [Required]
        public string Title{ get; set; }

        [Required]
        public string Forename{ get; set; }

        [Required]
        public List<Address> Addresses { get; set; }
}

Address Model:

public class Address {
        [Required]
        [StringLength(8, MinimumLength = 5)]
        public string Postcode{ get; set; }

        [Required]
        public string Town{ get; set; }
}

Controller Action:

public IActionResult Post([FromBody] Case item)
        {
            if (item == null)
            {
                return BadRequest(new ErrorMessage
                {
                    Message = "Request object is empty",
                    StatusCode = 400
                });
            }

             // This works and validates only the Case object but doesn't validate the 
            // Address object inside the Case object
            var validationContext = new ValidationContext(item, null, null);
            var validationResults = new List<ValidationResult>();
            Validator.TryValidateObject(item, validationContext, validationResults, true);

            // This always says the model is valid
            var isValid = TryValidateModel(item);

            // This always says the model is valid
            if (!ModelState.IsValid)
            {
                return BadRequest(new ErrorMessage
                {
                    Message = "ModelState is not valid. Check the ModelState property for specific errors.",
                    StatusCode = 400,
                    ModelState = ModelState.ToDictionary()
                });
            }

            // model is fine so do some processing here

            return Ok();
        }

Using Postman I post the following:

{
    "CaseReference":"ABC123",
    "Addresses": [{"Postcode":"a"}]
}

How can i post a json Case object to this controller action and have ModelState validate it and show correctly that for example "Title" and "Forename" are required and also to validate the properties of the Address object that are missing e.g. "Town".

I would really appreciate some help with the above issue.

question

Most helpful comment

You need AddMvcCore().AddDataAnnotations(). https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.DataAnnotations/DependencyInjection/MvcDataAnnotationsMvcCoreBuilderExtensions.cs#L25

AddMvcCore() is minimal. If you're looking for something equivalent to old WebAPI you probably want AddMvcCore().AddJsonFormatters().AddAuthorization().AddDataAnnotations()

All 9 comments

What is ModelState.IsValid before calling TryValidateModel()? That call should not be necessary and will likely confuse things.

I commented out all code above the ModelState.IsValid in case it confuses things and it is valid (true) when it shouldn't be. I started with ModelState.IsValid and it was always true. Then I tried above it with TryValidateModel and that was coming as valid and then added the Validator.TryValidateObject to see if that validates correctly.

Thanks for the added information

Apologies i should have added my Startup.cs file as well.

I have managed to make some progress and isolate what causes the issue.

In my startup ConfigureServices when I use the services.AddMvcCore() then the ModelState.IsValid is always valid but when I use the services.AddMvc() then it validates correctly.

public void ConfigureServices(IServiceCollection services)
        {
            // This works
            services.AddMvc();

            // This doesnt work
            services.AddMvcCore();
        }

Is there something extra that i'm missing when using MvcCore instead of Mvc ? Can it be made to work with MvcCore instead of Mvc?

You need AddMvcCore().AddDataAnnotations(). https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.DataAnnotations/DependencyInjection/MvcDataAnnotationsMvcCoreBuilderExtensions.cs#L25

AddMvcCore() is minimal. If you're looking for something equivalent to old WebAPI you probably want AddMvcCore().AddJsonFormatters().AddAuthorization().AddDataAnnotations()

That's great. Thank you very much.

Glad we could help!

I was looking for a solution for 4 hours. I think this should be in the documentation.

Thanks @rynowak it really helped me.

Was this page helpful?
0 / 5 - 0 ratings