Reputation: 33917
If a form like the one below is submitted and MyField
is left blank on the form, then by default Asp.Net Core model binding will place null into the corresponding property on the model as indicated below.
Example Form
<form asp-controller="SomeController" asp-action="SomeAction">
<label asp-for="MyField">My Field</label><input asp-for="MyField" type="text" />
<button type="submit">Submit</button>
</form>
Example Model
public class MyModel{
public string MyField { get; set; }
}
Example Action Method
[HttpPost]
public IActionResult Post(MyModel m) {
//m.MyField will be null if the field was left empty
//but I want it set to a blank string by the model binder
}
However, since MyField
is actually transmitted in the Http Post body I'd prefer that the model binder set the MyField
property on the model to a blank string rather than setting it to null. I'd prefer to reserve null for cases where MyField
is not transmitted in the Http Post body. How can the model binder be changed to exhibit this behavior?
Upvotes: 14
Views: 8199
Reputation: 60942
Adding my 2c just in case if you want to override ConvertEmptyStringToNull
behavior at parameter level in an action method this is how you do it (works in .NET 5, .NET 6, probably later versions too):
Suppose you have an action method in your controller like this:
public IActionResult DoStuff(int id, string name)
And you want to be able to pass empty-string to the "name" parameter.
Step 1 - add this class:
[AttributeUsage(AttributeTargets.Parameter)]
public class AllowEmptyAttribute : DisplayFormatAttribute
{
public AllowEmptyAttribute() : base() { ConvertEmptyStringToNull = false; }
}
Step 2 - use in controller
public IActionResult DoStuff(int id, [AllowEmpty] string name)
This might be hacky way to change it, but it works.
Upvotes: 1
Reputation: 33917
Studying the ASP.NET Core code for SimpleTypeModelBinder
at https://github.com/aspnet/Mvc/blob/rel/1.1.3/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/SimpleTypeModelBinder.cs I could see that there is a ModelMetadata.ConvertEmptyStringToNull
setting which is set to true by default that is causing the blank string to be converted to null on data binding. But the property is read only so at first I couldn't figure out how to changes its value.
@rsheptolut's post on this page https://github.com/aspnet/Mvc/issues/4988 led me to a solution.
Solution:
The value has to get set at startup. This can be done via this class:
public class CustomMetadataProvider : IMetadataDetailsProvider, IDisplayMetadataProvider {
public void CreateDisplayMetadata(DisplayMetadataProviderContext context) {
if (context.Key.MetadataKind == ModelMetadataKind.Property) {
context.DisplayMetadata.ConvertEmptyStringToNull = false;
}
}
}
When it's hooked into MvcOptions in the ConfigureServices
method of the startup.cs file like so
services.AddMvc()
.AddMvcOptions(options => options.ModelMetadataDetailsProviders.Add(new CustomMetadataProvider ()));
Now site wide, the default for a blank field that is posted back will be for the data binder to set the corresponding model property to a blank string rather than to null. Yea!
Upvotes: 19
Reputation: 36736
Have you tried making the property have a default value of empty string?
public string MyField { get; set; } = string.Empty;
an uglier solution to try is:
private string myField = string.Empty;
public string MyField
{
get { return myField ?? string.Empty; }
set { myField = value; }
}
I think it should work
Upvotes: 0