I was trying to create a simple ASP.NET Core form with model binding. When I went to configure the validation for that property, I figured it would be pretty simple. I wanted that field to be optional -- as in -- I wanted an empty string to be valid. Nope. Not easy at all. Turns out there's an issue with nullability and model binding.
BTW, here's the source code: Benday.NonNullableStringValidation.zip
Person Model with an Optional Notes Value
I recreated this as a simpler demo. Let's say that I have a Person class with FirstName
, LastName
, and Notes
properties.
I want FirstName
and LastName
to be required and then I wanted Notes
to be optional. Basically, I wanted string.Empty
to be a valid value for Notes
.
My guess was that I could add [Required(AllowEmptyStrings = true)]
to that property and make it work.
public class Person
{
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
[Required(AllowEmptyStrings = true)]
public string Notes { get; set; } = string.Empty;
}
My cshtml file is pretty unremarkable. I'm just using the standard asp-
helper attributes to enable validation.
@model Benday.NonNullableStringValidation.Api.Person
@{
ViewData["Title"] = "Edit";
}
<h1>Edit Person</h1>
<h4>Person</h4>
<hr />
<form asp-action="Index" method="post">
@Html.ValidationSummary()
<div class="row">
<div class="col-md-4">
<div class="form-group mb-3">
<label asp-for="FirstName" class="control-label"></label>
<input asp-for="FirstName" class="form-control" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<div class="form-group mb-3">
<label asp-for="LastName" class="control-label"></label>
<input asp-for="LastName" class="form-control" />
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<div class="form-group mb-3">
<label asp-for="Notes" class="control-label"></label>
<input asp-for="Notes" class="form-control" />
<span asp-validation-for="Notes" class="text-danger"></span>
</div>
</div>
</div>
<div class="form-group mb-3">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
@section Scripts {
@{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
}
Run the App → "The Notes field is required"
So I ran the application and set values for FirstName and LastName and left the Notes field blank. When I clicked Save, I got an error saying "The Notes field is required."
Well, that's annoying.

The Problem is Nullability
At the root of the problem is how nulls are handled in ASP.NET Core and C#. All this stuff that I'm doing in ASP.NET MVC and Razor is based on something called "Model Binding". This all was written before nullability checks and the nullable syntax in C#. So in the case of a string
variable, that value could be null
...or it could be an empty string...or it could be a non-empty string.
The default behavior with model binding is that if it sees an empty string, it tries to convert it to null
. You'd think that adding [Required(AllowEmptyStrings = true)]
would fix it but it doesn't. That AllowEmptyStrings
value just doesn't work because reasons.
I could change the Notes property to be nullable.
public string? Notes { get; set; }
If I changed that type to string?
and then removed the [Required]
attribute entirely, that would fix the problem immediately. But then that would mean that I'm hauling around a nullable property just to keep ASP.NET Core validation happy.
That's silly. Not doing that.
AI was no help.
As an aside, I'd like to say that AI was no help here. ChatGPT and Copilot both insisted that all I had to do was to remove the [Required]
attribute. Totally wrong. A hundred thousand billion percent wrong. All kinds of wrong.
What's my point? I dunno. My point was that AI was wrong. And I had to search around on the internet and read a whole bunch of stuff...like an animal.
(shrug)
The Solution: Change the Defaults in ASP.NET Core
I eventually found the solution kinda buried in the documentation.
ASP.NET Core Controllers and Views automatically make all the non-nullable properties on a class required. Which I guess makes sense. But that breaks down when you're all about non-nullability.
There's a configuration option for ASP.NET Core that changes that default behavior for non-nullable reference types like my string
property value.
In your Program.cs
for your ASP.NET Core application, you need to set the following configuration option:
builder.Services.AddControllersWithViews(
options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);
Setting SuppressImplicitRequiredAttributeForNonNullableReferenceTypes
to true makes the ASP.NET Core logic a little smarter about those types.
Here's the start of my Program.cs class for the ASP.NET Core project (below). Find the line that says AddControllers()
or AddControllersWithViews()
and add the option settings.
var builder = WebApplication.CreateBuilder(args);
// CHANGE THIS...
// builder.Services.AddControllersWithViews();
// ...TO THIS
builder.Services.AddControllersWithViews(options =>
{
options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true;
});
var app = builder.Build();
...
There's a Catch → Don't Forget to Add [Required]
There's a tiny little catch here with this setting. Without the setting, every string value is automatically tagged as Required
. With this setting turned off, you can now make properties optional but you also have to explicitly tag the fields that are required with the actual [Required]
attribute.
Back to the Person
class...I wanted FirstName
and LastName
to be required and Notes
to be optional. With SuppressImplicitRequiredAttributeForNonNullableReferenceTypes turned off, that means that this is what my Person class looks like now.
using System.ComponentModel.DataAnnotations;
namespace Benday.NonNullableStringValidation.Api;
public class Person
{
[Required()]
public string FirstName { get; set; } = string.Empty;
[Required()]
public string LastName { get; set; } = string.Empty;
// NOTE: No [Required] attribute on this property
// means that it allows empty strings
public string Notes { get; set; } = string.Empty;
}
Summary
Null checks in C# are fantastic but there are still some places that they cause little problems. ASP.NET Core Validation is one of those places. If you want better control over string validation in ASP.NET Core and you don't want to use nullable strings, considering changing your application's setting for SuppressImplicitRequiredAttributeForNonNullableReferenceTypes
.
Here's the source code: Benday.NonNullableStringValidation.zip
I hope this helped.
-Ben