2016-07-14 19 views
6

Trong ASP.NET Core 1.0, tôi có một triển khai tùy chỉnh các giao diện ILoggerProviderILogger. Tôi muốn có thể truy cập vào HttpContext từ phương thức Log.Truy cập vào HttpContext hiện tại từ một ILogger

Có vẻ như tôi cần phải tiêm IHttpContextAccessor vào tùy chỉnh ILogger, nhưng không thể tìm thấy cách thực hiện điều đó. Đối tượng ILoggerProvider được tạo khi khởi động và phương thức CreateLogger không cho phép chèn phụ thuộc.

Có cách nào đơn giản để sử dụng tiêm phụ thuộc với ILogger không?

Trả lời

6

Dưới đây là một ví dụ

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

Tuỳ chỉnh 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; 
    } 
} 

Mặc dù trên cách làm việc, tôi muốn thực hiện tùy chỉnh IRequestLogger thay vì tiêm HttpContextAccessor. Thực hiện là như dưới đây (nó không được kiểm tra):

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

Và việc sử dụng đơn giản:

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

Xin lỗi, tôi đăng câu trả lời của tôi và sau đó nhìn thấy bạn đánh bại tôi vào nó. Điều này là hoàn chỉnh hơn anyway, vì vậy tôi đã bỏ phiếu nó lên. –

2

tôi đã không kiểm tra mã này, nhưng tôi tin rằng phương pháp này sẽ là một cái gì đó như sau.

Trong lớp Startup.cs của bạn, đăng ký một HttpContextAccessor bằng cách thêm dòng sau vào ConfigureServices phương pháp:

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 

Sau đó, thêm một tham số bổ sung cho IHttpContextAccessor httpContextAccessor với phương pháp Configure (vẫn còn bên Startup.cs), một cái gì đó như :

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

Bên trong phương pháp Configure này, bạn có thể thêm tại gọi một phương pháp khuyến nông trên máy logger để tạo log tùy chỉnh của bạn pr ovider, một cái gì đó như:

loggerFactory.AddMyCustomProvider(httpContextAccessor); 

nơi phương pháp mở rộng (mà bạn cần phải tạo ra) sẽ là một cái gì đó như:

public static class MyCustomLoggerExtensions 
    { 
    public static ILoggerFactory AddMyCustomProvider(
     this ILoggerFactory factory, 
     IHttpContextAccessor httpContextAccessor) 
    { 
     factory.AddProvider(new MyCustomLoggerProvider(httpContextAccessor)); 
     return factory; 
    } 
    } 
Các vấn đề liên quan