MinimalApis.Extensions
MinimalApis.Extensions copied to clipboard
Combining Validated with a Record Struct Leads to InvalidProgram at Runtime
Steps to reproduce.
-
dotnet new webapi -minimal
. - Add reference to minimalapis.extensions.
- Replace Program.cs with the following.
using Microsoft.AspNetCore.Http.HttpResults;
using MinimalApis.Extensions.Binding;
using System.ComponentModel.DataAnnotations;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsMetadataProviderApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapPost(
"/inventory-accounts",
Results<Ok<PostInventoryAccountRequest>, ValidationProblem> (
Validated<PostInventoryAccountRequest> req) =>
{
if (!req.IsValid)
{
return TypedResults.ValidationProblem(req.Errors);
}
return TypedResults.Ok(req.Value);
});
app.Run();
public record struct PostInventoryAccountRequest
{
[Required]
public string Id { get; set; }
};
Finally run up the app and hit the POST method via swagger UI. The following exception will be raised.
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidProgramException: Common Language Runtime detected an invalid program.
at RouteHandler.Execute(PostInventoryAccountRequest req, HttpContext httpContext)
at lambda_method4(Closure , Object , HttpContext , Object )
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass46_3.<<HandleRequestBodyAndCompileRequestDelegate>b__2>d.MoveNext()
--- End of stack trace from previous location ---
at MinimalApis.Extensions.Binding.DefaultBinder`1.GetValueAsync(HttpContext httpContext, ParameterInfo parameter) in /_/src/MinimalApis.Extensions/Binding/DefaultBinderOfT.cs:line 32
at MinimalApis.Extensions.Binding.Validated`1.BindAsync(HttpContext context, ParameterInfo parameter) in /_/src/MinimalApis.Extensions/Binding/ValidatedOfT.cs:line 102
at Microsoft.AspNetCore.Http.ParameterBindingMethodCache.<ConvertValueTask>g__ConvertAwaited|18_0[T](ValueTask`1 typedValueTask)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass46_1.<<HandleRequestBodyAndCompileRequestDelegate>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
I am not entirely sure what is going on here but I think it could possibly be related to a bug with records mentioned over here -> https://stackoverflow.com/questions/70904674/why-does-this-tiny-program-give-common-language-runtime-detected-an-invalid-pro
I also understand that record structs are probably not meant to be used in this way, but when I saw the exception I thought it was interesting and worth making a quick issue about. I tested this on 6.0.5 originally, and found that the same thing happens on preview 4 of dotnet 7 with the built in version of this library.
Finally I wanted to say thanks for creating this library! I have had a lot of fun playing around with minimal APIs and these extensions improve the experience. Im excited for the future direction and functionality coming!