logging - .NetCore 数据库 ILoggerProvider 存储库上下文 null
问题描述
我正在尝试构建一个自定义 LoggerProvider,它通过存储库/dbcontext 将所有日志写入数据库。我在 ConfigureServices 中添加了日志记录,并在 Configure 中添加了新的提供程序,如下所示
public void ConfigureServices(IServiceCollection services)
{
//Register EntityFramework Core Datacontext for Dependency Injection
services.AddDbContext<DataContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
//Register Repositories for Dependency Injection
services.AddScoped<ILogRepository, LogRepository>();
services.AddScoped<ICountryRepository, CountryRepository>();
services.AddLogging();
//Add CORS
services.AddCors(options =>
{
options.AddPolicy("Open", builder =>
{
builder.AllowAnyOrigin();
builder.AllowAnyHeader();
builder.AllowAnyMethod();
});
});
services.AddControllers()
.AddMvcOptions(o =>
{
//Allow XML as a request Accept type
o.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory log, ILogRepository logRepo)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//Add Database Logging Provider
log.AddProvider(new LoggerDatabaseProvider(logRepo));
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseCors("Open");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
我创建了一个标准 LogRepository,它使用在 ConfigureServices 中注册的数据上下文
public class LogRepository : ILogRepository, IDisposable
{
private DataContext _dataContext;
public LogRepository(DataContext dataContext)
{
_dataContext = dataContext ?? throw new ArgumentNullException(nameof(dataContext));
}
public async Task<IEnumerable<Log>> GetAllAsync()
{
return await _dataContext.Logs.ToListAsync();
}
public async Task<Log> GetByIdAsync(int id)
{
return await _dataContext.Logs.FirstOrDefaultAsync(c => c.Id == id);
}
public async Task<Log> CreateAsync(Log log)
{
var addedEntity = _dataContext.Logs.Add(log);
await _dataContext.SaveChangesAsync();
return addedEntity.Entity;
}
public async Task UpdateAsync(int id, Log log)
{
if (!await ExistsAsync(id))
return;
_dataContext.Entry(log).State = EntityState.Modified;
await _dataContext.SaveChangesAsync();
}
public async Task DeleteAsync(int id)
{
var foundEntity = await GetByIdAsync(id);
if (foundEntity == null)
return;
_dataContext.Logs.Remove(foundEntity);
await _dataContext.SaveChangesAsync();
}
public async Task<bool> ExistsAsync(int id)
{
return await _dataContext.Logs.AnyAsync(c => c.Id == id);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(disposing)
{
if(_dataContext != null)
{
_dataContext.Dispose();
_dataContext = null;
}
}
}
}
这是 ILogger 的实现
public class LoggerDatabaseProvider : ILoggerProvider
{
private ILogRepository _repo;
public LoggerDatabaseProvider(ILogRepository 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 ILogRepository _repo;
public Logger(string categoryName, ILogRepository 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)
{
RecordMsg(logLevel, eventId, state, exception, formatter);
}
private void RecordMsg<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
_repo.CreateAsync(new Log
{
LogLevel = logLevel.ToString(),
CategoryName = _categoryName,
Message = formatter(state, exception),
CreatedDate = DateTime.Now
});
}
public IDisposable BeginScope<TState>(TState state)
{
return new NoopDisposable();
}
private class NoopDisposable : IDisposable
{
public void Dispose()
{
}
}
}
}
我从我的 APIController 调用记录器,如下所示
private readonly ICountryRepository _repository;
private readonly ILogger _logger;
public CountriesController(ICountryRepository countryRepository, ILogger logger)
{
_repository = countryRepository ?? throw new ArgumentNullException(nameof(countryRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
// GET: api/Country
[HttpGet]
public async Task<IActionResult> GetAll()
{
_logger.LogInformation($"{nameof(_repository)}: GetAll");
var countries = await _repository.GetAllAsync();
return Ok(countries);
}
我在我的 LogRepository 上放置了一个断点,当我到达那个断点时,我看到有一个 DataContext。但是,当调用 LogInformation 并查看存储库时,DataContext 为 NULL。我错过了什么?
解决方案
根据您的代码,我发现您已经在 LogRepository 类中设置了 Dispose 方法来处理 dbcontext。
这就是调用 LogRepository 方法时 dbcontext 为 null 的原因。
我建议您可以删除_dataContext.Dispose
让 DI 管理 LogRepository 和 dbcontext 的方法,然后它会运行良好。
更多细节,您可以参考以下代码:
public class LogRepository : ILogRepository, IDisposable
{
private TestDbcontext _dataContext;
public LogRepository(TestDbcontext dataContext)
{
_dataContext = dataContext ?? throw new ArgumentNullException(nameof(dataContext));
}
public async Task<IEnumerable<Log>> GetAllAsync()
{
return await _dataContext.Logs.ToListAsync();
}
public async Task<Log> GetByIdAsync(int id)
{
return await _dataContext.Logs.FirstOrDefaultAsync(c => c.Id == id);
}
public async Task<Log> CreateAsync(Log log)
{
var addedEntity = _dataContext.Logs.Add(log);
await _dataContext.SaveChangesAsync();
return addedEntity.Entity;
}
public async Task UpdateAsync(int id, Log log)
{
if (!await ExistsAsync(id))
return;
_dataContext.Entry(log).State = EntityState.Modified;
await _dataContext.SaveChangesAsync();
}
public async Task DeleteAsync(int id)
{
var foundEntity = await GetByIdAsync(id);
if (foundEntity == null)
return;
_dataContext.Logs.Remove(foundEntity);
await _dataContext.SaveChangesAsync();
}
public async Task<bool> ExistsAsync(int id)
{
return await _dataContext.Logs.AnyAsync(c => c.Id == id);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
//if (disposing)
//{
// if (_dataContext != null)
// {
// _dataContext.Dispose();
// _dataContext = null;
// }
//}
}
}
推荐阅读
- c# - 在 ASP.NET Core 中应用 Microsoft Authenticator App 来批准/拒绝 2FA
- python - 如何在 HDF5 中加载多个对象(列表列表)?
- python - Pandas iterrows 在函数内不起作用
- python - Plotnine - 在同一图表中添加垂直线和直方图
- firebase - 我似乎无法将我在 Firestore 中的数据复制到 algolia
- reactjs - react app with webpack/babel 在 IE 浏览器上显示为空白
- java - 如何解决 Stripe xamarin 绑定错误?(CS0103 当前上下文中不存在名称“开始”)
- bash - 如何修复此脚本 - 递归 ffmpeg 编码
- python - Firefox 无法连接到服务器 ws://192.168.0.15:9000/
- powershell - 如何使用 PowerShell 排除 CSV 中的特定行?