I'm upgrading from .NET classic to .NET Core 8 on a backend - it would be preferable to not have to change the frontend (even if it would be far better, this is beyond the scope of this project which is large enough as it is).
-----------------------------223163892637736061113378850953
Content-Disposition: form-data; name="SubscriptionFinAccountID"
null
The model looks like this:
public class SettingsModel
{
...
public int? SubscriptionFinAccountID { get; set; }
}
The controller method looks like this:
[HttpPost(nameof(SaveAccountSettings))]
public IActionResult SaveAccountSettings([FromForm]DefaultAccountSettings model)
The Property SubscriptionFinAccountID is a nullable int. However, the null in the Form-Data is treated like a string and thus cannot be converted to an int value.
Is there a way to override the model binding when using the [FromForm] attribute?
(The result above should be that the property SubscriptionFinAccountID should be set to null instead of throwing a parsing error which is the default)
You could solve this by implement a custom model binder, when property value equals to string "null" , bind property to null.
MyModelBinder.cs
public class MyModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var model = new SettingsModel();
foreach (var prop in typeof(SettingsModel).GetProperties())
{
var value = bindingContext.ValueProvider.GetValue(prop.Name).FirstValue;
if (value == "null")
{
prop.SetValue(model, null);
}
else
{
prop.SetValue(model, value);
}
}
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
Controller
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpPost(nameof(SaveAccountSettings))]
public IActionResult SaveAccountSettings([ModelBinder(typeof(MyModelBinder))] SettingsModel model)
{
var result = model;
return Ok(result);
}
}
---------------------update-----------------------
Binder works for every model type
public class MyModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var modelType = bindingContext.ModelType;
var model=Activator.CreateInstance(modelType);
foreach (var prop in modelType.GetProperties())
{
var value = bindingContext.ValueProvider.GetValue(prop.Name).FirstValue;
if (value == "null")
{
prop.SetValue(model, null);
}
else
{
prop.SetValue(model, value);
}
}
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
You could use [FromForm]
at the same time.
public IActionResult SaveAccountSettings([FromForm][ModelBinder(typeof(MyModelBinder))] SettingsModel model)