在ASP.NET Core 1.0中,我有ILoggerProvider
和ILogger
接口的自定义实现。我希望能够从Log
方法访问HttpContext。
我似乎需要在自定义IHttpContextAccessor
中注入ILogger
,但无法找到如何做到这一点。 ILoggerProvider
对象是在启动时创建的,CreateLogger
方法不允许依赖注入。
是否有一种使用ILogger
依赖注入的简单方法?
答案 0 :(得分: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 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;
}
}
虽然以上方式有效,但我更愿意实施自定义IRequestLogger
而不是注入HttpContextAccessor
。实现如下(未经测试):
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>");
//
});
}
答案 1 :(得分:2)
我还没有测试过这段代码,但我相信这种方法会如下所示。
在Startup.cs
类中,通过将以下行添加到ConfigureServices
方法来注册HttpContextAccessor:
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
然后,将IHttpContextAccessor httpContextAccessor
的其他参数添加到Configure方法(仍在Startup.cs
内),例如:
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
IHttpContextAccessor httpContextAccessor)
在此Configure
方法中,您可以立即添加在记录器工厂上调用扩展方法来创建自定义日志提供程序,如:
loggerFactory.AddMyCustomProvider(httpContextAccessor);
扩展方法(您需要创建)将是:
public static class MyCustomLoggerExtensions
{
public static ILoggerFactory AddMyCustomProvider(
this ILoggerFactory factory,
IHttpContextAccessor httpContextAccessor)
{
factory.AddProvider(new MyCustomLoggerProvider(httpContextAccessor));
return factory;
}
}