2016-07-14 9 views
6

In ASP.NET Core 1.0 habe ich eine benutzerdefinierte Implementierung der ILoggerProvider und Schnittstellen. Ich möchte auf den HttpContext von der Log Methode zugreifen können.Zugriff auf den aktuellen HttpContext von einem ILogger

Es scheint, dass ich eine IHttpContextAccessor in die benutzerdefinierte injizieren muss, aber kann nicht finden, wie man das macht. Das Objekt ILoggerProvider wird beim Start erstellt, und die Methode CreateLogger ermöglicht keine Abhängigkeitsinjektion.

Gibt es eine einfache Möglichkeit, Abhängigkeitsinjektion mit ILogger zu verwenden?

Antwort

6

Hier ist ein Beispiel

Startup.cs

public void ConfigureServices(IServiceCollection services) 
    { 
     services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 
    } 

    public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IServiceProvider serviceProvider) 
    { 
     loggerFactory.AddCustomLogger(serviceProvider.GetService<IHttpContextAccessor>()); 
     // 
    } 

Individuelle Logger:

public class CustomLogProvider : ILoggerProvider 
{ 

    private readonly Func<string, LogLevel, bool> _filter; 
    private readonly IHttpContextAccessor _accessor; 

    public CustomLogProvider(Func<string, LogLevel, bool> filter, IHttpContextAccessor accessor) 
    { 
     _filter = filter; 
     _accessor = accessor; 
    } 

    public ILogger CreateLogger(string categoryName) 
    { 
     return new CustomLogger(categoryName, _filter, _accessor); 
    } 

    public void Dispose() 
    { 
    } 
} 

public class CustomLogger : ILogger 
{ 
    private string _categoryName; 
    private Func<string, LogLevel, bool> _filter; 
    private readonly IHttpContextAccessor _accessor; 

    public CustomLogger(string categoryName, Func<string, LogLevel, bool> filter, IHttpContextAccessor accessor) 
    { 
     _categoryName = categoryName; 
     _filter = filter; 
     _accessor = accessor; 
    } 

    public IDisposable BeginScope<TState>(TState state) 
    { 
     return null; 
    } 

    public bool IsEnabled(LogLevel logLevel) 
    { 
     return (_filter == null || _filter(_categoryName, logLevel)); 
    } 

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) 
    { 
     if (!IsEnabled(logLevel)) 
     { 
      return; 
     } 

     if (formatter == null) 
     { 
      throw new ArgumentNullException(nameof(formatter)); 
     } 

     var message = formatter(state, exception); 

     if (string.IsNullOrEmpty(message)) 
     { 
      return; 
     } 

     message = $"{ logLevel }: {message}"; 

     if (exception != null) 
     { 
      message += Environment.NewLine + Environment.NewLine + exception.ToString(); 
     } 
     if(_accessor.HttpContext != null) // you should check HttpContext 
     { 
      message += Environment.NewLine + Environment.NewLine + _accessor.HttpContext.Request.Path; 
     } 
     // your implementation 

    } 

} 
public static class CustomLoggerExtensions 
{ 
    public static ILoggerFactory AddCustomLogger(this ILoggerFactory factory, IHttpContextAccessor accessor, 
              Func<string, LogLevel, bool> filter = null) 
    { 
     factory.AddProvider(new CustomLogProvider(filter, accessor)); 
     return factory; 
    } 
} 

Obwohl über Art und Weise funktioniert, ich würde es vorziehen, benutzerdefinierte IRequestLogger statt HttpContextAccessor Injektion zu implementieren. Die Umsetzung ist wie unten (es wird nicht geprüft):

public interface IRequestLogger<T> 
{ 
    void Log(LogLevel logLevel, EventId eventId, string message); // you can change this 
} 

public class RequestLogger<T> : IRequestLogger<T> 
{ 
    private readonly IHttpContextAccessor _accessor; 
    private readonly ILogger _logger; 
    public RequestLogger(ILogger<T> logger, IHttpContextAccessor accessor) 
    { 
     _accessor = accessor; 
     _logger = logger; 
    } 

    public void Log(LogLevel logLevel, EventId eventId, string message) 
    { 
     Func<object, Exception, string> _messageFormatter = (object state, Exception error) => 
     { 
      return state.ToString(); 
     }; 
     _logger.Log(LogLevel.Critical, 0, new FormattedLogValues(message), null, _messageFormatter); 
    } 
} 

Und einfache Nutzung:

public class LogType 
{ 

} 
public void ConfigureServices(IServiceCollection services) 
{ 
    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 
    services.AddSingleton(typeof(IRequestLogger<>), typeof(RequestLogger<>)); 
} 

public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) 
{ 
    loggerFactory.AddConsole(true); 
    app.Run(async (context) => 
    { 
     var requestLogger = context.RequestServices.GetService<IRequestLogger<LogType>>(); 
     requestLogger.Log(LogLevel.Critical, 11, "<message>"); 
     // 
    }); 
} 
+0

Sorry, posted ich meine Antwort, und dann haben Sie mich, um es zu schlagen. Das ist sowieso vollständiger, also habe ich es gewählt. –

2

Ich habe diesen Code nicht getestet, aber ich glaube, der Ansatz so etwas wie die folgenden sein.

In Ihrer Startup.cs Klasse, registrieren Sie einen HttpContextAccessor durch die folgende Zeile in die ConfigureServices Methode hinzu:

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 

Dann einen zusätzlichen Parameter für die IHttpContextAccessor httpContextAccessor zu konfigurieren Methode (noch innerhalb Startup.cs), etwas hinzufügen, wie :

public void Configure(
         IApplicationBuilder app, 
         IHostingEnvironment env, 
         ILoggerFactory loggerFactory, 
         IHttpContextAccessor httpContextAccessor) 

Innerhalb dieser Configure Methode können Sie nun eine Erweiterungsmethode auf der Logger Fabrik erstellen Sie Ihr benutzerdefiniertes Protokoll pr hinzufügen aufrufe ovider, so etwas wie:

loggerFactory.AddMyCustomProvider(httpContextAccessor); 

, wo die Erweiterungsmethode (die Sie erstellen müssen) wird wie etwas sein:

public static class MyCustomLoggerExtensions 
    { 
    public static ILoggerFactory AddMyCustomProvider(
     this ILoggerFactory factory, 
     IHttpContextAccessor httpContextAccessor) 
    { 
     factory.AddProvider(new MyCustomLoggerProvider(httpContextAccessor)); 
     return factory; 
    } 
    }