Skip to content

IHostApplicationLifetime StopApplication not respected in AspNetCore.Mvc.Testing #25857

Open
@GeeWee

Description

@GeeWee

Describe the bug

I'm trying to run integration tests, with some things that call IHostApplicationLifetime.StopApplication from an IHostedService

In a "real project" this works, but it does not when using the TestServer.
Test case below

To Reproduce

namespace DefaultNamespace
{
    using System.Threading;
    using System.Threading.Tasks;
    using BetterHostedServices.Test;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Mvc.Testing;
    using Microsoft.AspNetCore.TestHost;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Xunit;

    public class Test
    {
// Dummy startup that does nothing
        public class TestStartup
        {
            public void ConfigureServices(IServiceCollection services)
            {
            }

            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
            }
        }

// Hosted Service that stops the application
        public class HostedServiceThatShutsDown : IHostedService
        {
            private IHostApplicationLifetime lifetime;

            public HostedServiceThatShutsDown(IHostApplicationLifetime lifetime)
            {
                this.lifetime = lifetime;
            }

            public Task StartAsync(CancellationToken cancellationToken)
            {
                this.lifetime.StopApplication();
                return Task.CompletedTask;
            }

            public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
        }

// WebApplicationFactory with a few modifications so it can stand-alone
        public class TestWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
        {
            protected override void ConfigureWebHost(IWebHostBuilder builder)
            {
                builder.UseSolutionRelativeContentRoot(
                    "./tests/IntegrationUtils"); // Just because I have a custom dir in my project, can disregard
            }

            //from https://stackoverflow.com/questions/61159115/asp-net-core-testing-no-method-public-static-ihostbuilder-createhostbuilders
            protected override IHostBuilder CreateHostBuilder()
            {
                var builder = Host.CreateDefaultBuilder()
                    .ConfigureWebHostDefaults(x =>
                    {
                        x.UseStartup<DummyStartup>();
                    });
                return builder;
            }
        }

        [Fact]
        public void IssueRepro()
        {
            var factory = new TestWebApplicationFactory<TestStartup>()
                .WithWebHostBuilder(b =>
                    b.ConfigureTestServices(services =>
                    {
                        services.AddHostedService<HostedServiceThatShutsDown>();
                    }));

            var client = factory.CreateClient();

            // Works fine, but it shouldn't. The createClient above should error
            client.GetAsync("/");
        }
    }
}

The IHostedService calls StopApplication. I then don't expect the GetAsync call to work then.
The logs look like this:

info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/geewee/programming/BetterHostedServices/tests/IntegrationUtils
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET http://localhost/  
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished in 18.5779ms 404 

So it starts off by writing "Application is shutting down" and then proceeds to start the application.

Further technical details

  • ASP.NET Core version: 3.1
  • Include the output of dotnet --info
.NET Core SDK (reflecting any global.json):
 Version:   3.1.401
 Commit:    39d17847db

Runtime Environment:
 OS Name:     fedora
 OS Version:  32
 OS Platform: Linux
 RID:         fedora.32-x64
 Base Path:   /usr/share/dotnet/sdk/3.1.401/

Host (useful for support):
  Version: 3.1.7
  Commit:  fcfdef8d6b

.NET Core SDKs installed:
  2.2.402 [/usr/share/dotnet/sdk]
  3.0.103 [/usr/share/dotnet/sdk]
  3.1.401 [/usr/share/dotnet/sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.2.8 [/usr/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.2.8 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.3 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.7 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.2.8 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.3 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.7 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

To install additional .NET Core runtimes or SDKs:
  https://aka.ms/dotnet-download
  • The IDE (VS / VS Code/ VS4Mac) you're running on, and it's version
    Rider, but I don't think that matters. All of this is run from the Console.

Metadata

Metadata

Assignees

No one assigned

    Labels

    affected-fewThis issue impacts only small number of customersarea-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionsbugThis issue describes a behavior which is not expected - a bug.investigateseverity-minorThis label is used by an internal tool

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions