Way to generate 4xx response when non-nullable model property setter throws ArgumentNullException
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
Not sure how to categorize this issue, but it comes down this: what is the best way to (or how can I) make it so that if a model binder (whether that is request body JSON deserializion or form fields or whatever) gets an `ArgumentNullException` when attempting to set a non-nullable model property, MVC/web api/minimal API will return a 4xx response code? For example:
```cs
public class SomeDTO
{
private string _someValue = string.Empty;
public string SomeValue
{
get => _someValue;
set => _someValue = value ?? throw new ArgumentNullException(nameof(value));
}
}
```
JSON Payload:
```js
{
"SomeValue" = null
}
```
Right now, deserialization of this DTO causes a 500 internal server error response, which is not really appropriate given the circumstances. This is problematic when projects use something like `NullGuard.Fody` or `RuntimeNullables.Fody` where non-nullable reference type properties get automatic null checks injected into the setters. It should not be required to remove these null checks on DTOs.
I would like to provide a low-impact `RuntimeNullables.AspNet` package that users can add, which will provide an extension method that can be called on startup configuration such as `app.UseNullableModelPropertyHandling()` or a similar approach that will provide the desired behavior in this situation, which is to return a `4xx` reponse with a message indicating what property had been invalidly attempted to be set to a `null` value, but I don't know what approach would be ideal for this.
- `IModelValidator` seems to be too late, the exception has already been thrown by then.
- AFAICT, a custom model binder would require me to replicate the actual model binder selection logic, which does not seem ideal. I'm not sure how I could get the offending property name with this approach either.
- I don't believe middleware can differentiate between an `ArgumentNullException` that *should* return 5xx and a model property setter `ArgumentNullException` that should not, and again not sure how I would get the offending property name.
Minimal APIs appear to pose additional constraints on approaches given the source generators and interceptors.
Is there a way for me to accomplish this?
Contributor guide
Assessment
This issue has not been assessed yet.