Implementing a new .NET 6 Web API, I have added SeriLog hoping to handle exceptions through a custom ExceptionFilterAttribute and general HTTPContext entry/exit event logging but I am getting an error when the API is called.
I added Serilog via Program.cs
like so:
var logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.Enrich.FromLogContext()
.CreateLogger();
builder.Logging.ClearProviders();
builder.Logging.AddSerilog(logger);
Logging via ILogger.LogInformation in the controller is fine but when I try and use ILogger from an Attribute or implementation of IResourceAttribute it throws a Dependency Injection exception.
I.e. when I introduce some Attributes that use the ILogger like so to the Program.cs:
builder.Services.AddControllers(options =>
{
options.Filters.Add<MyErrorHandlingAttribute>();
});
The Attribute class looks like:
public class MyErrorHandlingAttribute: ExceptionFilterAttribute
{
private readonly ILogger _logger;
public MyErrorHandlingAttribute(ILogger logger)
{
_logger= logger?? throw new ArgumentNullException(nameof(logger));
}
}
Exception:
System.InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate 'MessageOrchestrator.Common.Attributes.MyErrorHandlingAttribute'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method2(Closure , IServiceProvider , Object[] ) at Microsoft.AspNetCore.Mvc.TypeFilterAttribute.CreateInstance(IServiceProvider serviceProvider) at Microsoft.AspNetCore.Mvc.Filters.DefaultFilterProvider.ProvideFilter(FilterProviderContext context, FilterItem filterItem) at Microsoft.AspNetCore.Mvc.Filters.DefaultFilterProvider.OnProvidersExecuting(FilterProviderContext context) at Microsoft.AspNetCore.Mvc.Filters.FilterFactory.CreateUncachedFiltersCore(IFilterProvider[] filterProviders, ActionContext actionContext, List`1 filterItems)
at Microsoft.AspNetCore.Mvc.Filters.FilterFactory.GetAllFilters(IFilterProvider[] filterProviders, ActionContext actionContext) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerCache.GetCachedResult(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Routing.ControllerRequestDelegateFactory.<>c__DisplayClass12_0.b__0(HttpContext context) at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) --- End of stack trace from previous location --- at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Sorry am quite new to SeriLog and would be grateful for any advice.
When using dependency injection, you need to inject a concrete ILogger<T>
in your constructor, like e.g. ILogger<ExceptionFilterAttribute>
.
From the documentation
To create logs, use an
ILogger<TCategoryName>
object from dependency injection (DI).
The ASP.NET Core web apps use
ILogger<T>
to automatically get anILogger
instance that uses the fully qualified type name ofT
as the category.
Your code will then look like below.
public class MyErrorHandlingAttribute: ExceptionFilterAttribute
{
private readonly ILogger _logger;
public MyErrorHandlingAttribute(ILogger<ExceptionFilterAttribute> logger)
{
_logger= logger ?? throw new ArgumentNullException(nameof(logger));
}
}