dotnet / dotnet/aspnetcore

Host stopped and disposed twice when WebApplicationFactory<> is used with the minimal api

Open
#40,271 22 comments 22 reactions 0 assignees View on GitHub
area-hosting
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 5h
Merged PRs (30d)
276

Description

### Is there an existing issue for this?

- [X] I have searched the existing issues

### Describe the bug

**Description**
When using `WebApplicationFactory<>` together with the minimal api `WebApplication`, the underlying `Host` is stopped and disposed twice from separate threads.

This can lead to integration tests failing e.g. when there are custom `IHostedService`s registered. Dpending on the race condition, a particular instance of `IHostedService` can be in order: stopped, then disposed, then attempted to stop again from a different thread; or attempted to stop twice from different threads at the same time.

**What happens under the hood**

With minimal api and the `WebApplicationFactory`, the whole `Program` content is executed. It goes up to `Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.WaitForShutdownAsync()` and waits for the `IHostApplicationLifetime.ApplicationStopping` event.

The test runs and at the end the WebApplicationFactory is being disposed. It calls (with some wrapper classes skipped here for brevity) `Microsoft.Extensions.Hosting.Internal.Host.StopAsync()`

The `Host.StopAsync()` calls `ApplicationLifetime.StopApplication()`, and thus raises the beforementioned `IHostApplicationLifetime.ApplicationStopping` event, thus unblocking the "main" thread executing `HostingAbstractionsHostExtensions.WaitForShutdownAsync()`, which then... calls `Host.StopAsync()` again.

### Expected Behavior

`Host` and any registered `IHostedService`s should be stopped and disposed once.

### Steps To Reproduce

https://github.com/mateusz-duchnowski-trainline/disposing-host-twice-issue

run `dotnet test`

example output, where `A` is an `IHostedService`:
```
[xUnit.net 00:00:01.19] DisposingHostTwiceIssue.Tests: A started
[xUnit.net 00:00:01.28] DisposingHostTwiceIssue.Tests: A stopping
[xUnit.net 00:00:01.28] DisposingHostTwiceIssue.Tests: A stopping
[xUnit.net 00:00:01.50] DisposingHostTwiceIssue.Tests: A stopped
[xUnit.net 00:00:01.50] DisposingHostTwiceIssue.Tests: A stopped
```

### Exceptions (if any)

_No response_

### .NET Version

6.0.200-preview.22055.15

### Anything else?

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.