我想知道IServiceCollection.AddDbContext()
如何添加我的ApplicationDbContext
。我的猜测是不是作为单例添加的,并且每个请求都创建一个新的实例。
我正在实现一个自定义的ILoggerProvider
,它需要一个ApplicationDbContext
的实例。
我的问题是:如果我的ILoggerProvider
被配置为单例,但它依赖于ApplicationDbContext
不是单例,会发生什么?
是的,但是使用来自ILogger的DbContext并不是最好的主意。日志记录器和日志接收器是独立的实体。
从单例中使用有作用域的服务并不罕见。后台服务就是这种情况,它被注册为单例。在后台任务中使用作用域服务一节中解释了使用作用域服务。
要使用作用域(或瞬态)服务,单例需要访问IServiceProvider
。这通常作为构造函数依赖项传递。
public class MyHostedService : BackgroundService
{
private readonly ILogger<MyHostedService> _logger;
public MyHostedService(IServiceProvider services,
ILogger<MyHostedService> logger)
{
Services = services;
_logger = logger;
}
}
该类可用于使用IServiceProvider检索瞬态实例。GetService或GetRequiredService:
var service = Services.GetRequiredService<MyTransientService>();
要使用有作用域的服务,单例需要显式地创建作用域并从该作用域检索服务。当释放作用域时,所有作用域实例也将被释放
using (var scope = Services.CreateScope())
{
var context =
scope.ServiceProvider
.GetRequiredService<MyDbContext>();
...
context.SaveChanges();
}
日志记录器和数据库
ILogger不需要依赖于DbContext。日志库使用单独的接口来发布和存储日志条目。ILogger
实例用于发布日志条目,而不是存储它。存储日志事件是日志接收器或日志提供程序的工作-不同的日志库对此使用不同的名称。
。. NET Core有意提供很少的日志接收。有非常好的日志库,比如Serilog,而且。net Core团队并不想重复他们的工作。他们确实为Azure Application Insights等微软特定的服务提供了一些sink实现。
可以编写一个自定义日志接收器来写入数据库,但最好使用已经提供此功能的现有库,并负责缓冲,异步操作等。写入数据库总是比写入本地文件更昂贵,因此数据库接收器需要缓冲消息以减少对应用程序的影响。
很容易集成一个现有的库,如Serilog. aspnetcore。
public static int Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateLogger();
....
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog() // <-- Add this line
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
该库反过来提供了数据库接收器,如serilog . sink . sqlserver .
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.MSSqlServer(
connectionString: "Server=localhost;Database=LogDb;Integrated Security=SSPI;",
sinkOptions: new MSSqlServerSinkOptions { TableName = "LogEvents" })
.CreateLogger();
SQL Server接收器将创建日志表并开始向其写入日志条目。UseSerilog()
调用将把所有ILogger
调用重定向到Serilog,并最终重定向到数据库表。