According to this answer we cannot resolve a logger to log messages or exceptions from the ConfigureServices
method in Startup
. This is a problem for me because I have code in ConfigureServices
which is written to throw exceptions if required settings are missing. Is there any other way that I can log that exception?

- 27,588
- 3
- 45
- 62
2 Answers
Exceptions inside ConfigureServices
method can be thrown from two different sources:
- From the
ConfigureServices
method code itself. - From Factory methods passed to the DI container.
Example:
services.AddScoped<IDependency>(sp =>
{
// Any Exception from here
});
I pointed these two scenarios because I have found that they resolve using different approaches.
Scenario 1: Same approach used in this answer Answer1 (using that startup class, maybe adjusting how the exception is handled inside Configure method)
Scenario 2:
This scenario is even harder because the try/catch used in scenario 1 doesn't catch exceptions thrown from Factory methods. But in those cases we have access to the ServiceProvider
so we can handle exception inside each factory method with something like this.
services.AddScoped<IService>(sp =>
{
var httpContext = sp.GetService<IHttpContextAccessor>().HttpContext;
var logger = sp.GetService<ILogger<IService>>();
try
{
throw new Exception("Text Exception");
}
catch (Exception ex)
{
// log
logger.LogError(ex, ex.Message);
// status error
httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
httpContext.Response.ContentType = "application/json";
await httpContext.Response.WriteAsync(ex.Message);
return null;
}
});

- 121
- 1
- 6
Yes, there is a way to log an exception thrown from ConfigureServices
. It's just a bit of hack. Maybe it's not a terrible hack. You decide.
ConfigureServices
runs before Configure
. We can inject a logger into Configure
. So the hack is to hang on to the exception we throw in ConfigureServices
, then log and rethrow it from the Configure
method.
It's easiest to see it all at once, so here's a sample Startup
:
public class Startup
{
private Exception _configureServicesException;
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
try
{
// Configure all of your services
}
catch (Exception ex)
{
_configureServicesException = ex;
}
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
try
{
if (_configureServicesException != null)
{
ExceptionDispatchInfo.Capture(_configureServicesException).Throw();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
catch (Exception ex)
{
logger.LogError(
ex,
"Exception thrown when starting application in {Environment} environment",
env.EnvironmentName);
throw;
}
}
}
Here's what's been added:
private Exception _configureServicesException;
is a field for storing an exception thrown fromConfigureServices
.- If
ConfigureServices
throws an exception, we store it in that field and continue without rethrowing it. - We've added an
ILogger
argument toConfigure
so that the runtime will inject a logger. (More on that in a moment.) - When the runtime calls
Configure
, then if an exception was thrown fromConfigureServices
, we'll rethrow it. In this example we'll catch, log, and rethrow any exception thrown inConfigure
, including the one that we captured fromConfigureServices
.
All of this assumes that we've configured logging before this point. How to that is detailed in this Microsoft documentation - "Capture logs within ASP.NET Core startup code".
Reproducing the example from that page:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureLogging((context, builder) =>
{
// Providing an instrumentation key is required if you're using the
// standalone Microsoft.Extensions.Logging.ApplicationInsights package,
// or when you need to capture logs during application startup, for example
// in the Program.cs or Startup.cs itself.
builder.AddApplicationInsights(
context.Configuration["APPINSIGHTS_CONNECTIONSTRING"]);
// Capture all log-level entries from Program
builder.AddFilter<ApplicationInsightsLoggerProvider>(
typeof(Program).FullName, LogLevel.Trace);
// Capture all log-level entries from Startup
builder.AddFilter<ApplicationInsightsLoggerProvider>(
typeof(Startup).FullName, LogLevel.Trace);
});
...the key detail being that we're configuring logging so that the runtime can inject a logger when we call
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)

- 27,588
- 3
- 45
- 62
-
1Are you not able to capture exception on `Build` or host `Run*` and log via an external logger at the program level? This is an interesting approach/hack you have here. – Nkosi Jun 29 '21 at 20:23
-
I'd have to see exactly what you're referring to. Perhaps you could supply a different answer. I'm not thrilled to death with mine which is why I call it a hack. But it's easy to read and understand. There's exactly one point in the application where I need to log before logging has been configured. – Scott Hannen Jun 29 '21 at 20:44