.NET 6 WebApplicationFactory test throws System.InvalidOperationException : The entry point exited without ever building an IHost.
See original GitHub issueDescription
When I have Serilog configured on my Program.cs and if I run more than one test that uses WebApplicationFactory I get an exception thrown System.InvalidOperationException : The entry point exited without ever building an IHost. accessing the application factory services.
Reproduction
Program.cs
using System.Text.Json.Serialization;
using Serilog;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateBootstrapLogger();
Log.Information("Starting up...");
try
{
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog((ctx, lc) => lc.ReadFrom.Configuration(ctx.Configuration));
var configuration = builder.Configuration;
var services = builder.Services;
// Add services to the container.
services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
})
.AddControllersAsServices();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
var app = builder.Build();
app.UseSerilogRequestLogging();
app.UseCors(builder =>
builder
.WithOrigins(configuration.GetSection("AllowedOrigins")
.AsEnumerable()
.Select(kvp => kvp.Value)
.Where(origin => !string.IsNullOrEmpty(origin))
.ToArray()
)
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly.");
return 1;
}
finally
{
Log.CloseAndFlush();
}
#pragma warning disable CA1050 // Declare types in namespaces
public partial class Program { } // so you can reference it in tests
#pragma warning restore CA1050 // Declare types in namespaces
appsettings.json:
{
"AllowedHosts": "*",
"Serilog": {
"AllowedHosts": "*",
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Enrich": [
"FromLogContext"
],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "@mt = 'An unhandled exception has occurred while executing the request.'"
}
}
],
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} [{Level}]: {Message:l}{NewLine}{Exception}"
}
}
]
}
}
TestApplication.cs:
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Hosting;
namespace Api.Tests;
internal class TestApplication : WebApplicationFactory<Program>
{
private readonly string environment;
public TestApplication(string environment = "Development")
{
this.environment = environment;
}
protected override IHost CreateHost(IHostBuilder builder)
{
builder.UseEnvironment(environment);
return base.CreateHost(builder);
}
}
SwaggerTest.cs:
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
using Swashbuckle.AspNetCore.Swagger;
using Xunit;
namespace Api.Tests.Swagger;
public class SwaggerTest
{
[Fact]
public async Task OperationIds_Should_Be_Unique()
{
await using var application = new TestApplication();
var swaggerProvider = application.Services.GetRequiredService<ISwaggerProvider>();
var swagger = swaggerProvider.GetSwagger("v1");
var operationIds = swagger.Paths.Values.SelectMany(path => path.Operations.Values.Select(operation => operation.OperationId)).ToList();
operationIds.Should().OnlyHaveUniqueItems();
}
[Fact]
public async Task OperationIds_Should_Be_Unique2()
{
await using var application = new TestApplication();
var swaggerProvider = application.Services.GetRequiredService<ISwaggerProvider>();
var swagger = swaggerProvider.GetSwagger("v1");
var operationIds = swagger.Paths.Values.SelectMany(path => path.Operations.Values.Select(operation => operation.OperationId)).ToList();
operationIds.Should().OnlyHaveUniqueItems();
}
}
Expected behavior Tests pass, and does not throw calling application.Services
Relevant package, tooling and runtime versions
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="Serilog.Expressions" Version="3.2.1" />
dotnet --version:
6.0.102
Additional context
The tests pass if I comment out the line builder.Host.UseSerilog((ctx, lc) => lc.ReadFrom.Configuration(ctx.Configuration)); from Program.cs.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:9
- Comments:28 (7 by maintainers)
Top Results From Across the Web
The entry point exited without ever building an IHost
The error "The entry point exited without ever building an IHost" generally happens when the host failed to start because it crashed. A...
Read more >Supporting integration tests with WebApplicationFactory in ...
NET 6 entrypoint, so failed at this point throw new InvalidOperationException();. This method uses a new type, DeferredHostBuilder , which we'll ...
Read more >[Fix]-The entry point exited without ever building an IHost
What is the point of configuring DefaultScheme and DefaultChallengeScheme on ASP.NET Core? The command "npm run build -- --prod" exited with code 1...
Read more >Integration Testing: IHost Lifecycle with xUnit.Net
The generic host builder introduced in .Net Core turns out to be a very effective way to bootstrap your system within automated test...
Read more >Using custom startup class with ASP.NET Core integration ...
Custom location for web host builder confuses integration tests mechanism and we have to point out the correct location of web application ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Changing Serilog initialization in
Program.csfrom:to:
solved the problem. @nblumhardt could you explain why is that?
Same issue here.
This is an ugly issue IMO because if you try and do everything right by following the Serilog docs and use
CreateBootstrapLogger()and you follow the official Microsoft Integration Testing Docs which recommend creating test classes withITestFixture<CustomWebAppFactory<Program>>by default everything will run in parallel and you will hit this bug and then spend maybe hours fighting it before you land here on this issue from Google.Maybe the Serilog docs could be improved to warn of this? IE:
Or maybe there is a way for someone much smarter than me to maker a change in
CreateBootstrapLogger()to circumvent this issue?