-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Descriptive Error for Improper Use of [AsParameters] with IFormFileCollection in .NET 8 Minimal APIs #56114
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
Comments
The stack trace here doesn't seem to be anything to do with Minimal APIs - it's to do with MassTransit. What exception do you get if you temporarily remove your background service? It could be that one problem is causing another, but then that problem masks the original error, meaning it looks like you get a terrible error message. |
To clarify, the error message is indeed a result of using the [AsParameters] attribute incorrectly. The issue isn't related to MassTransit or other dependencies, as we encountered this problem in a nearly empty project as well. The error message generated is over 300K characters, making it impractical to post in full here. It encompasses details from various components of our project, including MassTransit, Hangfire, MediatR, etc., leading to a convoluted stack trace. Here’s an example in a minimal setup: Reproducible Example: app.MapPost("err", ([AsParameters]List<IFormFile> files) => "OK"); Resulting Error: crit: Microsoft.AspNetCore.Hosting.Diagnostics[6]
Application startup exception
System.InvalidProgramException: Common Language Runtime detected an invalid program.
at System.Reflection.Emit.DynamicMethod.CreateDelegate(Type delegateType, Object target)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
at System.Linq.Expressions.Expression`1.Compile()
at Microsoft.AspNetCore.Http.RequestDelegateFactory.HandleRequestBodyAndCompileRequestDelegateForForm(Expression responseWritingMethodCall, RequestDelegateFactoryContext factoryContext)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(Delegate handler, RequestDelegateFactoryOptions options, RequestDelegateMetadataResult metadataResult)
at Microsoft.AspNetCore.Routing.RouteEndpointDataSource.CreateRouteEndpointBuilder(RouteEntry entry, RoutePattern groupPrefix, IReadOnlyList`1 groupConventions, IReadOnlyList`1 groupFinallyConventions)
at Microsoft.AspNetCore.Routing.RouteEndpointDataSource.get_Endpoints()
at Microsoft.AspNetCore.Routing.CompositeEndpointDataSource.CreateEndpointsUnsynchronized()
at Microsoft.AspNetCore.Routing.CompositeEndpointDataSource.EnsureEndpointsInitialized()
at Microsoft.AspNetCore.Routing.CompositeEndpointDataSource.get_Endpoints()
at Microsoft.AspNetCore.Routing.DataSourceDependentCache`1.Initialize()
at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func`1 valueFactory)
at Microsoft.AspNetCore.Routing.DataSourceDependentCache`1.EnsureInitialized()
at Microsoft.AspNetCore.Authorization.Policy.AuthorizationPolicyCache..ctor(EndpointDataSource dataSource)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier serviceIdentifier)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware..ctor(RequestDelegate next, IAuthorizationPolicyProvider policyProvider, IServiceProvider services)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddlewareInternal..ctor(RequestDelegate next, IServiceProvider services, IAuthorizationPolicyProvider policyProvider, ILogger`1 logger)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
at Microsoft.Extensions.Internal.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.ReflectionMiddlewareBinder.CreateMiddleware(RequestDelegate next)
at Microsoft.AspNetCore.Builder.ApplicationBuilder.Build()
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
fail: Microsoft.Extensions.Hosting.Internal.Host[11]
Hosting failed to start
System.InvalidProgramException: Common Language Runtime detected an invalid program.
at System.Reflection.Emit.DynamicMethod.CreateDelegate(Type delegateType, Object target)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
at System.Linq.Expressions.Expression`1.Compile()
at Microsoft.AspNetCore.Http.RequestDelegateFactory.HandleRequestBodyAndCompileRequestDelegateForForm(Expression responseWritingMethodCall, RequestDelegateFactoryContext factoryContext)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(Delegate handler, RequestDelegateFactoryOptions options, RequestDelegateMetadataResult metadataResult)
at Microsoft.AspNetCore.Routing.RouteEndpointDataSource.CreateRouteEndpointBuilder(RouteEntry entry, RoutePattern groupPrefix, IReadOnlyList`1 groupConventions, IReadOnlyList`1 groupFinallyConventions)
at Microsoft.AspNetCore.Routing.RouteEndpointDataSource.get_Endpoints()
at Microsoft.AspNetCore.Routing.CompositeEndpointDataSource.CreateEndpointsUnsynchronized()
at Microsoft.AspNetCore.Routing.CompositeEndpointDataSource.EnsureEndpointsInitialized()
at Microsoft.AspNetCore.Routing.CompositeEndpointDataSource.get_Endpoints()
at Microsoft.AspNetCore.Routing.DataSourceDependentCache`1.Initialize()
at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func`1 valueFactory)
at Microsoft.AspNetCore.Routing.DataSourceDependentCache`1.EnsureInitialized()
at Microsoft.AspNetCore.Authorization.Policy.AuthorizationPolicyCache..ctor(EndpointDataSource dataSource)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier serviceIdentifier)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware..ctor(RequestDelegate next, IAuthorizationPolicyProvider policyProvider, IServiceProvider services)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddlewareInternal..ctor(RequestDelegate next, IServiceProvider services, IAuthorizationPolicyProvider policyProvider, ILogger`1 logger)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
at Microsoft.Extensions.Internal.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.ReflectionMiddlewareBinder.CreateMiddleware(RequestDelegate next)
at Microsoft.AspNetCore.Builder.ApplicationBuilder.Build()
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>b__15_1(IHostedService service, CancellationToken token)
at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](IEnumerable`1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List`1 exceptions, Func`3 operation)
Unhandled exception. System.InvalidProgramException: Common Language Runtime detected an invalid program.
at System.Reflection.Emit.DynamicMethod.CreateDelegate(Type delegateType, Object target)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
at System.Linq.Expressions.Expression`1.Compile()
at Microsoft.AspNetCore.Http.RequestDelegateFactory.HandleRequestBodyAndCompileRequestDelegateForForm(Expression responseWritingMethodCall, RequestDelegateFactoryContext factoryContext)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(Delegate handler, RequestDelegateFactoryOptions options, RequestDelegateMetadataResult metadataResult)
at Microsoft.AspNetCore.Routing.RouteEndpointDataSource.CreateRouteEndpointBuilder(RouteEntry entry, RoutePattern groupPrefix, IReadOnlyList`1 groupConventions, IReadOnlyList`1 groupFinallyConventions)
at Microsoft.AspNetCore.Routing.RouteEndpointDataSource.get_Endpoints()
at Microsoft.AspNetCore.Routing.CompositeEndpointDataSource.CreateEndpointsUnsynchronized()
at Microsoft.AspNetCore.Routing.CompositeEndpointDataSource.EnsureEndpointsInitialized()
at Microsoft.AspNetCore.Routing.CompositeEndpointDataSource.get_Endpoints()
at Microsoft.AspNetCore.Routing.DataSourceDependentCache`1.Initialize()
at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func`1 valueFactory)
at Microsoft.AspNetCore.Routing.DataSourceDependentCache`1.EnsureInitialized()
at Microsoft.AspNetCore.Authorization.Policy.AuthorizationPolicyCache..ctor(EndpointDataSource dataSource)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier serviceIdentifier)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware..ctor(RequestDelegate next, IAuthorizationPolicyProvider policyProvider, IServiceProvider services)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddlewareInternal..ctor(RequestDelegate next, IServiceProvider services, IAuthorizationPolicyProvider policyProvider, ILogger`1 logger)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
at Microsoft.Extensions.Internal.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.ReflectionMiddlewareBinder.CreateMiddleware(RequestDelegate next)
at Microsoft.AspNetCore.Builder.ApplicationBuilder.Build()
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>b__15_1(IHostedService service, CancellationToken token)
at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](IEnumerable`1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List`1 exceptions, Func`3 operation)
at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
at Program.<Main>$(String[] args) in C:\Users\HIDEDPATH\Program.cs:line 35 We have spent more than an hour until we have found the error in our case. |
Thanks - that looks like it contains enough information now for someone to look into. |
I believe the root cause of the issue in both of these cases is the fact that parameter annotated with the I see two different strategies for solving this:
The first approach has the benefit of "shifting left" the error and alerting users earlier in the dev loop that their handler is invalid. The second approach won't warn users until they send the first request to the app but is easier to roll out. I'm putting this in the backlog for now although I'm happy to review a PR or provide pointers as to how we can go about fixing it. |
Hi, I am able to setup the environment and replicate the problem. for (var i = 0; i < properties.Length; i++)
{
// For parameterless ctor we will init only writable properties.
if (properties[i].CanWrite && properties[i].GetSetMethod(nonPublic: false) != null)
{
//new code begin
// if properties cant be construct ,throw error
if (properties[i].PropertyType.IsInterface)
{
throw new NotSupportedException($" {nameof(AsParametersAttribute)} is not supported for complex or recursive model binding");
}
//end
var parameterInfo = new PropertyAsParameterInfo(properties[i], factoryContext.NullabilityContext);
Debug.Assert(parameterInfo.Name != null, "Parameter name must be set for parameters resolved from properties.");
bindings.Add(Expression.Bind(properties[i], CreateArgument(parameterInfo, factoryContext, out var hasTryParse, out var hasBindAsync, out var _)));
factoryContext.Parameters.Add(parameterInfo);
factoryContext.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata(parameterInfo.Name, parameterInfo, hasTryParse: hasTryParse, hasBindAsync: hasBindAsync, isOptional: parameterInfo.IsOptional));
}
} Have I missed anything or should I place the check elsewhere? |
@jnzhsh I think the check should happen somewhere here and should be done on the parameter type instead of the properties. |
thanks else if (parameterCustomAttributes.OfType<AsParametersAttribute>().Any())
{
isAsParameters = true;
if (parameter is PropertyAsParameterInfo)
{
throw new NotSupportedException(
$"Nested {nameof(AsParametersAttribute)} is not supported and should be used only for handler parameters.");
}
if(parameter.ParameterType.GetInterfaces().Any(x => x.IsGenericType&& x.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
// Or one of the following judgments
// only check List<> and Dictionary<>
//if (parameter.ParameterType.IsConstructedGenericType && (parameter.ParameterType.GetGenericTypeDefinition() == typeof(List<>)|| parameter.ParameterType.GetGenericTypeDefinition() == typeof(Dictionary<,>)))
{
throw new NotSupportedException(
$" {nameof(AsParametersAttribute)} is not supported to complex model binding (eg IEnumerable<>) ");
}
return BindParameterFromProperties(parameter, factoryContext);
} |
I've tried to reproduce this issue for framework 8.0 Here is a simple Minimal API project here: https://github.com/smnsht/56114 used for testing. Lines 37-40 in Program.cs are commented out. In order to view problems, Here is what I found:
Bug reproduces? Getting a short stack trace with the message
Bug reproduces? Getting a short stack trace with message Looks like the problem exists for List<>, arrays, and probably for Dictionary. |
Is there an existing issue for this?
Describe the bug
Problem Description
In .NET 8 minimal APIs, when using the
[AsParameters]
attribute on anIFormFileCollection
parameter, the resulting error message is extremely long and non-descriptive. This can make it difficult for developers to diagnose the issue.Example Code
The following endpoint works correctly:
However, if a developer mistakenly uses
[AsParameters]
like this:The error message returned by ASP.NET Core is long and unclear.
Actual Error Message
It is too long so I cannot copy paste it here but I left extract from it in the exception message place.
Expected Behavior
ASP.NET Core should provide a more descriptive and concise error message that clearly indicates the misuse of
[AsParameters]
withIFormFileCollection
. For example, it should state that[AsParameters]
is not supported withIFormFileCollection
.Steps To Reproduce
No response
Exceptions (if any)
Actual Error Message
.NET Version
8.0.2
Anything else?
No response
The text was updated successfully, but these errors were encountered: