diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/Internal/Host.cs b/src/libraries/Microsoft.Extensions.Hosting/src/Internal/Host.cs index e84d2f3a646215..153bd31d4bc51e 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/Internal/Host.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/src/Internal/Host.cs @@ -85,28 +85,27 @@ public async Task StartAsync(CancellationToken cancellationToken = default) cancellationToken.ThrowIfCancellationRequested(); List exceptions = new(); - _hostedServices ??= Services.GetRequiredService>(); - _hostedLifecycleServices = GetHostLifecycles(_hostedServices); _hostStarting = true; bool concurrent = _options.ServicesStartConcurrently; bool abortOnFirstException = !concurrent; - // Call startup validators. - IStartupValidator? validator = Services.GetService(); - if (validator is not null) + try { - try - { - validator.Validate(); - } - catch (Exception ex) - { - exceptions.Add(ex); + _hostedServices ??= Services.GetRequiredService>(); + _hostedLifecycleServices = GetHostLifecycles(_hostedServices); - // Validation errors cause startup to be aborted. - LogAndRethrow(); - } + // Call startup validators. + IStartupValidator? validator = Services.GetService(); + validator?.Validate(); } + catch (Exception ex) + { + // service factory or validation failed, abort startup. + exceptions.Add(ex); + LogAndRethrow(); + return; // unreachable + } + // Call StartingAsync(). if (_hostedLifecycleServices is not null) diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Internal/HostTests.cs b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Internal/HostTests.cs index 64f9dd8f904118..d5e03ebab1d08e 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Internal/HostTests.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Internal/HostTests.cs @@ -1426,6 +1426,33 @@ public async Task BackgroundServiceAsyncExceptionGetsLogged( } } + /// + /// Tests that an exception is logged if a hosted service factory fails. + /// + [Fact] + public async Task HostedServiceFactoryExceptionGetsLogged() + { + TestLoggerProvider logger = new TestLoggerProvider(); + + using IHost host = CreateBuilder() + .ConfigureLogging(logging => + { + logging.AddProvider(logger); + }) + .ConfigureServices((hostContext, services) => + { + services.AddHostedService(p => throw new InvalidOperationException("factory failed")); + }) + .Build(); + + await Assert.ThrowsAsync(() => host.StartAsync()); + + LogEvent[] events = logger.GetEvents(); + Assert.Single(events); + Assert.Equal(LogLevel.Error, events[0].LogLevel); + Assert.Equal("HostedServiceStartupFaulted", events[0].EventId.Name); + } + /// /// Tests that when a BackgroundService is canceled when stopping the host, /// no error is logged.