From b098f24c681f8943cdb1815392ef075f6b9e1141 Mon Sep 17 00:00:00 2001 From: mus65 Date: Thu, 20 Feb 2025 18:56:39 +0100 Subject: [PATCH] Host: log exception if a service factory fails (#112534) --- .../src/Internal/Host.cs | 29 +++++++++---------- .../tests/UnitTests/Internal/HostTests.cs | 27 +++++++++++++++++ 2 files changed, 41 insertions(+), 15 deletions(-) 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.