一个单例类可以有一个非单例依赖吗?



我想知道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,并最终重定向到数据库表。

最新更新