Trying to build a middleware that would log information for every request. ASP.NET Core 3.1 Learning some basics
I'm trying to understand some weird behavior. This is my constructor for middleware:
public ContextRequestLoggingMiddleware( RequestDelegate next, ILoggerFactory loggerFactory ) {
this._next = next;
_logger = loggerFactory.CreateLogger( "ContextRequestLoggingMiddleware" );
}
Using this works as expected. Message is logged on every request:
public async Task InvokeAsync (HttpContext context ) {
_logger.LogInformation( "test from middleware" );
await _next( context );
}
When I use code below:
_logger = loggerFactory.CreateLogger<ContextRequestLoggingMiddleware>();
Execution goes over _logger.LogInformation
but it seems like it is not executed, nothing is logged, no error, no problem, just jumps to next line of code. Looking into _logger with WatchList I do not see any difference between those two approaches.
The same behavior where nothing is logged, and no error is encountered if I use ILogger<T>
:
public ContextRequestLoggingMiddleware( RequestDelegate next,
ILogger<ContextRequestLoggingMiddleware> logger ) {
this._next = next;
_logger = logger;
}
I cannot inject plain ILogger
as it throws a runtime error:
Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate 'Microsoft.AspNetCore.Builder.ContextRequestLoggingMiddleware'.
Again inspecting object I do not see difference between different approaches I used. So why is this? I would consider ILogger<T>
as best choice, but why it does not work here? It does work for me in Controller. Thank you for explanation.
For context, my CreateHostBuilder
:
public static IHostBuilder CreateHostBuilder( string[] args ) =>
Host.CreateDefaultBuilder( args )
.ConfigureLogging( ( hostContext, loggingBuilder ) => {
loggingBuilder.ClearProviders();
loggingBuilder.AddConfiguration( hostContext.Configuration.GetSection( "Logging" ) );
loggingBuilder.AddCustomFileLogger();
}
).ConfigureWebHostDefaults( webBuilder => {
webBuilder.UseStartup<Startup>();
} );
And part of my Startup
class:
public void ConfigureServices( IServiceCollection services ) {
services.AddControllers();
services.AddDbContext<NPAContext>( options =>
options.UseSqlServer( Configuration.GetConnectionString( cnnDB ) ) );
services.AddAuthentication( options => {
options.DefaultAuthenticateScheme = ApiKeyAuthenticationOptions.DefaultScheme;
options.DefaultChallengeScheme = ApiKeyAuthenticationOptions.DefaultScheme;
} )
.AddApiKeySupport( options => { } );
services.AddSingleton<List<JobEventDTO>>();
}
public void Configure( IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory ) {
if ( env.IsDevelopment() ) {
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseContextRequestLoggingMiddleware();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints( endpoints => {
endpoints.MapControllers();
} );
}
Edit
Resolution:
I made a mistake, and when building class ContextRequestLoggingMiddleware
I placed it under NameSpace Microsoft.AspNetCore.Builder
. With this, the only way how to get logger to work in MiddleWare was passing ILoggerFactory, and creating logger, but it worked only one way
_logger = loggerFactory.CreateLogger( "ContextRequestLoggingMiddleware" )
Once I placed the class under different NameSpace, other approaches started working as well
_logger = loggerFactory.CreateLogger<ContextRequestLoggingMiddleware>()
And also passing ILogger<ContextRequestLoggingMiddleware>
now works
So building class as below now works for me. Interesting how change of namespace makes it work.
namespace NPARetrieval.Middleware {
public class ContextRequestLoggingMiddleware {
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public ContextRequestLoggingMiddleware( RequestDelegate next, ILogger<ContextRequestLoggingMiddleware> logger ) {
this._next = next;
_logger = logger;
}
public async Task InvokeAsync (HttpContext context ) {
_logger.LogInformation( "test from middleware" );
await _next( context );
}
}
}