我正在研究ASP.NET Core,我已经成功地使用文件系统实现了日志记录,但是如何使用数据库解决方案实现日志记录功能.如何将EF上下文传递给我的' LoggerDatabaseProvider',仍然将这两个解耦?下面的代码应该清除一些前期问题:
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddEntityFramework()
.AddEntityFrameworkSqlServer()
.AddDbContext<WorldContext>();
services.AddTransient<WorldContextSeedData>();
services.AddScoped<IWorldRepository, WorldRepository>();
//this one adds service with Dependency Injection that calls 'MyLogger' constructor with two parameters, instead the default one parametereless constructor.
services.AddScoped<ILogger, LoggerFileProvider.Logger>(provider => new LoggerFileProvider.Logger("CustomErrors", Startup.Configuration["Data:LogFilePath"]));
//services.AddScoped<ILogger, LoggerDatabaseProvider.Logger>(provider => new LoggerDatabaseProvider.Logger("CustomErrors"));
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, WorldContextSeedData seeder)
{
string basePath = Startup.Configuration["Data:LogFilePath"];
loggerFactory.AddProvider(new LoggerFileProvider(basePath));
loggerFactory.AddProvider(new LoggerDatabaseProvider());
app.UseStaticFiles();
app.UseMvc(config =>
{
config.MapRoute(
name: "Default",
template: "{controller}/{action}/{id?}",
defaults: new { controller = "App", action = "index" }
);
});
seeder.EnsureSeedData();
}
Run Code Online (Sandbox Code Playgroud)
这是我成功实现的带有文本文件的记录器:
public class LoggerFileProvider : ILoggerProvider
{
private readonly string _logFilePath;
public LoggerFileProvider(string logFilePath)
{
_logFilePath = logFilePath;
}
public ILogger CreateLogger(string categoryName)
{
return new Logger(categoryName, _logFilePath);
}
public void Dispose()
{
}
public class Logger : ILogger
{
private readonly string _categoryName;
private readonly string _path;
public Logger(string categoryName, string logFilePath)
{
_path = logFilePath;
_categoryName = categoryName;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
try
{
RecordMsg(logLevel, eventId, state, exception, formatter);
}
catch (Exception ex)
{
//this is being used in case of error 'the process cannot access the file because it is being used by another process', could not find a better way to resolve the issue
RecordMsg(logLevel, eventId, state, exception, formatter);
}
}
private void RecordMsg<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
string msg = $"{logLevel} :: {_categoryName} :: {formatter(state, exception)} :: username :: {DateTime.Now}";
using (var writer = File.AppendText(_path))
{
writer.WriteLine(msg);
}
}
public IDisposable BeginScope<TState>(TState state)
{
return new NoopDisposable();
}
private class NoopDisposable : IDisposable
{
public void Dispose()
{
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是如何实现非常相似,但是使用数据库解决方案呢?WorldContextEF利用我与数据库进行通信,但如果更容易,我可以使用我的存储库.我想保持上下文/存储库与LoggerDatabaseProvider我即将实现的' ' 分离,所以我可以在其他项目中使用它.
根据规范,这是我设法实现它的方式,以防万一有人会寻找类似的解决方案.
'Startup.cs':
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddEntityFramework()
.AddEntityFrameworkSqlServer()
.AddDbContext<WorldContext>();
services.AddLogging();
services.AddTransient<WorldContextSeedData>();
services.AddScoped<IMailService, MailServiceDebug>();
services.AddScoped<IWorldRepository, WorldRepository>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, WorldContextSeedData seeder, IWorldRepository worldRepo)
{
string basePath = Startup.Configuration["Data:LogFilePath"];
loggerFactory.AddProvider(new LoggerFileProvider(basePath));
loggerFactory.AddProvider(new LoggerDatabaseProvider(worldRepo));
app.UseStaticFiles();
app.UseMvc(config =>
{
config.MapRoute(
name: "Default",
template: "{controller}/{action}/{id?}",
defaults: new { controller = "App", action = "index" }
);
});
seeder.EnsureSeedData();
}
Run Code Online (Sandbox Code Playgroud)
自定义'LoggerFileProvider.cs':
public class LoggerFileProvider : ILoggerProvider
{
private readonly string _logFilePath;
public LoggerFileProvider(string logFilePath)
{
_logFilePath = logFilePath;
}
public ILogger CreateLogger(string categoryName)
{
return new Logger(categoryName, _logFilePath);
}
public void Dispose()
{
}
public class Logger : ILogger
{
private readonly string _categoryName;
private readonly string _path;
public Logger(string categoryName, string logFilePath)
{
_path = logFilePath;
_categoryName = categoryName;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
try
{
RecordMsg(logLevel, eventId, state, exception, formatter);
}
catch (Exception ex)
{
//this is being used in case of error 'the process cannot access the file because it is being used by another process', could not find a better way to resolve the issue
RecordMsg(logLevel, eventId, state, exception, formatter);
}
}
private void RecordMsg<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
string msg = $"{logLevel} :: {_categoryName} :: {formatter(state, exception)} :: username :: {DateTime.Now}";
using (var writer = File.AppendText(_path))
{
writer.WriteLine(msg);
}
}
public IDisposable BeginScope<TState>(TState state)
{
return new NoopDisposable();
}
private class NoopDisposable : IDisposable
{
public void Dispose()
{
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
自定义'LoggerDatabaseProvider.cs':
public class LoggerDatabaseProvider : ILoggerProvider
{
private IWorldRepository _repo;
public LoggerDatabaseProvider(IWorldRepository repo)
{
_repo = repo;
}
public ILogger CreateLogger(string categoryName)
{
return new Logger(categoryName, _repo);
}
public void Dispose()
{
}
public class Logger : ILogger
{
private readonly string _categoryName;
private readonly IWorldRepository _repo;
public Logger(string categoryName, IWorldRepository repo)
{
_repo = repo;
_categoryName = categoryName;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (logLevel == LogLevel.Critical || logLevel == LogLevel.Error || logLevel == LogLevel.Warning)
RecordMsg(logLevel, eventId, state, exception, formatter);
}
private void RecordMsg<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
_repo.Log(new Log
{
LogLevel = logLevel.ToString(),
CategoryName = _categoryName,
Msg = formatter(state, exception),
User = "username",
Timestamp = DateTime.Now
});
}
public IDisposable BeginScope<TState>(TState state)
{
return new NoopDisposable();
}
private class NoopDisposable : IDisposable
{
public void Dispose()
{
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6023 次 |
| 最近记录: |