Skip to content

Exception when running tests for an app that uses Minimal APIs #35990

@DamianEdwards

Description

@DamianEdwards

I have a project using Minimal APIs at https://github.com/DamianEdwards/MinimalApiPlayground/tree/main/src/MinimalApiPlayground

I started to add some tests for this project and at the point I had two tests classes with at least two test methods in each class the test run run would fail due to an exception, but only when running all tests. If I comment out the test that caused the exception, another test would cause it instead. If I ran just the tests from either class, it doesn't repro.

It seems to be caused by the fact that RequestDelegateFactory stores a static instance of NullabilityContext which is not a thread-safe class.

Exception details:

[xUnit.net 00:00:01.51]     MinimalApiPlayground.Tests.TodoApi.POST_FromFile_Invalid_Responds_BadRequest [FAIL]
  Failed MinimalApiPlayground.Tests.TodoApi.POST_FromFile_Invalid_Responds_BadRequest [729 ms]
  Error Message:
   System.ArgumentException : An item with the same key has already been added. Key: System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Http.IResult] <<Main>$>g__AddTodoFunc|0_22(Todo, TodoDb)
  Stack Trace:
     at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at System.Reflection.NullabilityInfoContext.GetNullableContext(MemberInfo memberInfo)
   at System.Reflection.NullabilityInfoContext.GetNullabilityInfo(MemberInfo memberInfo, Type type, IList`1 customAttributes, Int32 index)
   at System.Reflection.NullabilityInfoContext.Create(ParameterInfo parameterInfo)
   at Microsoft.AspNetCore.Http.RequestDelegateFactory.IsOptionalParameter(ParameterInfo parameter)
   at Microsoft.AspNetCore.Http.RequestDelegateFactory.BindParameterFromBody(ParameterInfo parameter, Boolean allowEmpty, FactoryContext factoryContext)
   at Microsoft.AspNetCore.Http.RequestDelegateFactory.CreateArgument(ParameterInfo parameter, FactoryContext factoryContext)
   at Microsoft.AspNetCore.Http.RequestDelegateFactory.CreateArguments(ParameterInfo[] parameters, FactoryContext factoryContext)
   at Microsoft.AspNetCore.Http.RequestDelegateFactory.CreateTargetableRequestDelegate(MethodInfo methodInfo, RequestDelegateFactoryOptions options, FactoryContext factoryContext, Expression targetExpression)
   at Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(Delegate handler, RequestDelegateFactoryOptions options)
   at Microsoft.AspNetCore.Builder.DelegateEndpointRouteBuilderExtensions.Map(IEndpointRouteBuilder endpoints, RoutePattern pattern, Delegate handler)
   at Microsoft.AspNetCore.Builder.DelegateEndpointRouteBuilderExtensions.MapMethods(IEndpointRouteBuilder endpoints, String pattern, IEnumerable`1 httpMethods, Delegate handler)
   at Microsoft.AspNetCore.Builder.DelegateEndpointRouteBuilderExtensions.MapPost(IEndpointRouteBuilder endpoints, String pattern, Delegate handler)
   at Program.<Main>$(String[] args) in C:\src\GitHub\DamianEdwards\MinimalApiPlayground\src\MinimalApiPlayground\Program.cs:line 214
   at Program.<Main>(String[] args)
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Testing.DeferredHostBuilder.DeferredHost.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Start(IHost host)
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.CreateHost(IHostBuilder builder)
   at MinimalApiPlayground.Tests.PlaygroundApplication.CreateHost(IHostBuilder builder) in C:\src\GitHub\DamianEdwards\MinimalApiPlayground\tests\MinimalApiPlayground.Tests\PlaygroundApplication.cs:line 31
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.ConfigureHostBuilder(IHostBuilder hostBuilder)
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.EnsureServer()
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.CreateDefaultClient(DelegatingHandler[] handlers)
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.CreateDefaultClient(Uri baseAddress, DelegatingHandler[] handlers)
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.CreateClient(WebApplicationFactoryClientOptions options)
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.CreateClient()
   at MinimalApiPlayground.Tests.TodoApi.POST_FromFile_Invalid_Responds_BadRequest() in C:\src\GitHub\DamianEdwards\MinimalApiPlayground\tests\MinimalApiPlayground.Tests\TodoApi.cs:line 42
   at MinimalApiPlayground.Tests.TodoApi.POST_FromFile_Invalid_Responds_BadRequest() in C:\src\GitHub\DamianEdwards\MinimalApiPlayground\tests\MinimalApiPlayground.Tests\TodoApi.cs:line 49
--- End of stack trace from previous location ---

Simplest repro code:

void Foo(Product? p) { }
var d = Foo;
Parallel.For(0, 100, _ =>
{
    var d1 = RequestDelegateFactory.Create(d);
});
record Product(int Id, string? Title);

Metadata

Metadata

Assignees

Labels

Priority:0Work that we can't release withoutarea-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcbugThis issue describes a behavior which is not expected - a bug.feature-minimal-actionsController-like actions for endpoint routingold-area-web-frameworks-do-not-use*DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions