ASP.NET CORE Required property validation
System.ComponentModel.DataAnnotations.Required validation doesn't work how most people imagine it working. Required - it does have value, if the property is nullable and value is null - this validation will fail. However, if we have value type property - then we always have value, and required validation never fails.
Model binder creates an empty model and assigns values from JSON. If a JSON value is missing for enum or integer - we will get default value, and sometimes this is not desired behavior. We can approach this problem from two sides, we can make value types nullable or we can use JSON validation and fail inside the model binder.
Lets explore these two validation types by creating small project, start with empty ASP.NET core API project.
Validation with System.ComponentModel.DataAnnotations
using System.ComponentModel.DataAnnotations;
namespace RequiredValidation
{
public class WeatherModel
{
[Required]
public int Temperature { get; set; }
[Required]
public string Title { get; set; }
}
}
Validation with NewtonsoftJson
Microsoft.AspNetCore.Mvc.NewtonsoftJson
public void ConfigureServices(IServiceCollection services)
{
services
.AddControllers()
.AddNewtonsoftJson();
using Newtonsoft.Json;
namespace RequiredValidation
{
public class Weather2Model
{
[JsonProperty(Required = Required.Always)]
public int Temperature { get; set; }
[JsonProperty(Required = Required.Always)]
public string Title { get; set; }
}
}
Endpoints
Controller endpoints in both cases are identical, no additional changes are needed. To make testing easier I just return same model.
[HttpPost]
[Route("Update")]
public IActionResult UpdateWeather(WeatherModel weather)
{
return Ok(weather);
}
[HttpPost]
[Route("Update2")]
public IActionResult UpdateWeather2(Weather2Model weather)
{
return Ok(weather);
}
Testing DataAnnotations validation
Lets start by testing DataAnnotations validation "Update" endpoint.
Testing JSON property validation
Summary
Back to C# basics, value types always have a default value - unless they are nullable. Adding required on value type property doesn't make sense since it will be with default value either it's zero or first enum value.