2016-07-14 14 views
6

ASP.NET Core 1.0では、ILoggerProviderと​​インターフェイスのカスタム実装があります。私はLogメソッドからHttpContextにアクセスできるようにしたいと思います。ILoggerから現在のHttpContextにアクセスします

​​にIHttpContextAccessorを注入する必要があるようですが、その方法を見つけることはできません。 ILoggerProviderオブジェクトは起動時に作成され、CreateLoggerメソッドは依存関係注入を許可しません。

​​で依存性注入を使用する簡単な方法はありますか?上記の方法は動作しますが、私はカスタムIRequestLogger代わりHttpContextAccessorを注入するのを実装することを好むだろう

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; 
    } 
} 

:ここ

答えて

6

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>()); 
     // 
    } 

カスタムロガーの例です。実装は、(それがテストされていません)以下のようなものです:

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); 
    } 
} 

、簡単な使い方:

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

申し訳ありませんが、私は私の答えを掲示して、あなたはそれに私を打つ見ました。これはとにかくより完全なので、私はそれを投票しました。 –

2

私はこのコードをテストしていませんが、私はアプローチは次のようなものになると考えています。 、そして、

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 

設定方法(まだStartup.cs内側)のような、何かにIHttpContextAccessor httpContextAccessorための追加のパラメータを追加します。あなたのStartup.csクラスで

は、ConfigureServicesメソッドに次の行を追加してHttpContextAccessorを登録します:このConfigureメソッド内

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

は、あなたがPR今追加カスタムログを作成するために、ロガー工場に拡張メソッドを呼び出すことができますovider、のようなもの:

拡張メソッドは、(あなたが作成する必要があること)のようなものになります
loggerFactory.AddMyCustomProvider(httpContextAccessor); 

public static class MyCustomLoggerExtensions 
    { 
    public static ILoggerFactory AddMyCustomProvider(
     this ILoggerFactory factory, 
     IHttpContextAccessor httpContextAccessor) 
    { 
     factory.AddProvider(new MyCustomLoggerProvider(httpContextAccessor)); 
     return factory; 
    } 
    } 
関連する問題