Skip to content

Minimal API : Converting empty string to Nullable (ex: int?) with [FromForm] binding #55202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
JimmyLahaie opened this issue Apr 18, 2024 · 12 comments
Closed
1 task done
Assignees
Labels
area-blazor Includes: Blazor, Razor Components area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-blazor-form-validation This issue is related to forms validation in Blazor

Comments

@JimmyLahaie
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

From a Minimal API project

With the HTML form

<form method="post" action="/SomeUrl">
<input type="text" name="someProp" />
<button type="submit">OK</button>
</form>

And Mapping
app.MapPost("/SomeUrl", ([FromForm] SomeModel theInputModel) => Results.Ok());

And Model

public class SomeModel
{
    public int? SomeProp { get; set; }
}

If I enter a number in "SomeProp" input field, it works ok.
But if I leave "SomeProp" input field empty and the submit the form, I get the exception:

Microsoft.AspNetCore.Http.BadHttpRequestException: The value '' is not valid for 'SomeProp'.

 ---> Microsoft.AspNetCore.Components.Endpoints.FormMapping.FormDataMappingException: An error occurred while trying to map a value from form data. For more details, see the 'Error' property and the 'InnerException' property.

        at Microsoft.AspNetCore.Components.Endpoints.FormMapping.FormDataReader.AddMappingError(Exception exception, String attemptedValue)

        at Microsoft.AspNetCore.Components.Endpoints.FormMapping.CompiledComplexTypeConverter`1.TryRead(FormDataReader& context, Type type, FormDataMapperOptions options, T& result, Boolean& found)

        at Microsoft.AspNetCore.Components.Endpoints.FormMapping.FormDataMapper.Map[T](FormDataReader reader, FormDataMapperOptions options)

        at lambda_method280(Closure, Object, HttpContext, Object)

        --- End of inner exception stack trace ---

        at Microsoft.AspNetCore.Http.RequestDelegateFactory.Log.FormDataMappingFailed(HttpContext httpContext, String parameterTypeName, String parameterName, FormDataMappingException exception, Boolean shouldThrow)

        at lambda_method280(Closure, Object, HttpContext, Object)

        at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass104_2.<<HandleRequestBodyAndCompileRequestDelegateForForm>b__2>d.MoveNext()

     --- End of stack trace from previous location ---

That is because the request sent to the server when posting the form is a POST with content :
someProp=

The only workaroung I found is using a string instead of int? and then convert string to int? by myself which is not the best solution.

Describe the solution you'd like

When binding [FromForm], I beleive that Minimal API should convert empty string to null when converting to a Nullable type (ex int?).
Or at least give any option to do so.

Additional context

No response

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Apr 18, 2024
@KennethHoff
Copy link

I've also experienced this issue. I "fixed" it by updating my frontend to delete all empty fields before sending it to the backend.

@amcasey amcasey added area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Apr 18, 2024
@captainsafia
Copy link
Member

The form binding behavior that minimal APIs uses is shared with Blazor. I'm open to changing this behavior to be more inline with how empty strings are handled elsewhere in minimal APIs (and in forms in MVC).

@javiercn Any objections to modifying the form binding behavior for empty strings here?

@captainsafia captainsafia added this to the Backlog milestone Apr 30, 2024
@captainsafia captainsafia removed their assignment Apr 30, 2024
@captainsafia captainsafia added area-blazor Includes: Blazor, Razor Components feature-blazor-form-validation This issue is related to forms validation in Blazor labels Apr 30, 2024
@dimenus
Copy link

dimenus commented Aug 6, 2024

@captainsafia I have this same issue with [FromQuery] as well with e.g. Nullable<long>. It works just fine when the parameter is omitted, but if the clients sends the query parameter with an empty value, the validation fails.

curl 'http://localhost:5209/proui/field?uiCodeTypeId='

Microsoft.AspNetCore.Http.BadHttpRequestException: Failed to bind parameter "Nullable<long> uiCodeTypeId" from "".
   at lambda_method34(Closure, Object, HttpContext)
   at Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

@dcernach
Copy link

dcernach commented Aug 6, 2024

@captainsafia I'm also experiencing issues with [AsParameters] and all Nullable primitive types. This is causing significant problems. As a workaround, I've implemented an Axios interceptor to remove empty, null, and undefined values, but some of our customers are unhappy with this solution. I've tried other approaches, including custom JSON converters, without success. Is there a plan to improve Minimal API model binding to match the behavior of MVC Model Binder?

If anyone's interested, here's my Axios interceptor:

const $http = axios.create({
    baseURL: '/your-endpoint'
}); 

function cleanObject(obj) {
    for (let propName in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, propName)) {
            if (obj[propName] === null || obj[propName] === undefined || obj[propName] === '') {
                delete obj[propName];
            }
        }
    }
    return obj;
}

$http.interceptors.request.use((req) => {
    if (req.data) req.data = cleanObject(req.data);
    if (req.params) req.params = cleanObject(req.params);
    return req;
});

@dcernach
Copy link

dcernach commented Aug 6, 2024

The form binding behavior that minimal APIs uses is shared with Blazor. I'm open to changing this behavior to be more inline with how empty strings are handled elsewhere in minimal APIs (and in forms in MVC).

@javiercn Any objections to modifying the form binding behavior for empty strings here?

Please do it :)

@SebastianToet
Copy link

SebastianToet commented Sep 26, 2024

This is still a big issue in Blazor SSR in the current .NET 9 preview: When a [SupplyParameterFromForm] model contains a nullable int (or double, etc.), an empty input value results in a form-binding validation error (and not in a null value without an error, as you would expect).

@halter73 halter73 modified the milestones: Backlog, .NET 10 Planning Oct 9, 2024
@xxnickles
Copy link

Unfortunatelly it seems few people are using minimal api and form binding as this issue is not getting traction. I just found out this behavior also impacts nullable enumeration bidding, which fails with the same error. I will assume the workaround is going to be not include the fields from the front end, but the behavior should match other areas of aspnet, in concrete I am talking about SupplyParameterFromForm from Blazor SSR, which this scenario works fine (at least with enumerations)

@danroth27 danroth27 added the Priority:2 Work that is important, but not critical for the release label Jan 13, 2025
@jamie-nzfunds
Copy link

Just ran into this issue too. It would be great to have a fix for this.

@captainsafia
Copy link
Member

There's been some recent action on a PR to fix this over at #52499.

@ndjonbor
Copy link

ndjonbor commented Jan 22, 2025

@captainsafia The PR you referenced seems to be specific to binding from forms. Are there any plans on the similar issue when binding from queries? I'm facing the same problem as mentioned by dimenus:

@captainsafia I have this same issue with [FromQuery] as well with e.g. Nullable<long>. It works just fine when the parameter is omitted, but if the clients sends the query parameter with an empty value, the validation fails.

curl 'http://localhost:5209/proui/field?uiCodeTypeId='

Microsoft.AspNetCore.Http.BadHttpRequestException: Failed to bind parameter "Nullable<long> uiCodeTypeId" from "".
   at lambda_method34(Closure, Object, HttpContext)
   at Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

In my case the parameter is a strongly typed ID which implements IParsable, and the parameter is nullable. I've had no luck with handling this particular scenario

@javiercn
Copy link
Member

We merged a community contribution for this:
#52499

But we still want to limit the change to a well-known subset of types.

@danroth27 danroth27 removed the Priority:2 Work that is important, but not critical for the release label Feb 19, 2025
@lewing
Copy link
Member

lewing commented Feb 20, 2025

fixed in #60498

@lewing lewing closed this as completed Feb 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-blazor-form-validation This issue is related to forms validation in Blazor
Projects
None yet
Development

No branches or pull requests