C# 在ASP.NET Core';斯迪
我使用的是最新的NLog,ASP.NET内核,EF内核 我编写了一个通过EF保存的自定义日志目标:C# 在ASP.NET Core';斯迪,c#,asp.net-core,entity-framework-core,nlog,C#,Asp.net Core,Entity Framework Core,Nlog,我使用的是最新的NLog,ASP.NET内核,EF内核 我编写了一个通过EF保存的自定义日志目标: public class MyEFTarget : TargetWithLayout { private readonly IMyContext _context; public MyEFTarget(IMyContext context) : base() { _context = context; } protected overr
public class MyEFTarget : TargetWithLayout
{
private readonly IMyContext _context;
public MyEFTarget(IMyContext context) : base()
{
_context = context;
}
protected override void Write(LogEventInfo logEvent)
{
// and so on...
}
}
我的启动
:
public void ConfigureServices(IServiceCollection services)
{
// register context with DI (as scoped)
services.AddDbContext<MyContext>(o => o.UseSqlite(config.GetConnectionString("Default")));
services.AddScoped<IMyContext, MyContext>();
// target depends on context, so must also be registered with DI
// I chose scoped so it's the same as the context
services.AddScoped<MyEFTarget>();
// ...and so on
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
{
// normal NLog config
env.ConfigureNLog("NLog.config");
loggerFactory.AddNLog();
app.AddNLogWeb();
// register target
Target.Register<MyEFTarget>("MyEFTarget");
// add target + rule programmatically
var target = serviceProvider.GetService<MyEFTarget>();
var rule = new LoggingRule("*", LogLevel.Info, target);
LogManager.Configuration.AddTarget("MyEFTarget", target); // problem is here ********
LogManager.Configuration.LoggingRules.Add(rule);
LogManager.ReconfigExistingLoggers();
// ...and so on
}
public void配置服务(IServiceCollection服务)
{
//向DI注册上下文(按作用域)
services.AddDbContext(o=>o.UseSqlite(config.GetConnectionString(“默认”));
services.addScope();
//目标依赖于上下文,所以也必须向DI注册
//我选择了作用域,因此它与上下文相同
services.addScope();
//……等等
}
public void Configure(IApplicationBuilder应用程序、IHostingEnvironment环境、,
iLogger工厂(loggerFactory,IServiceProvider服务提供商)
{
//正常非直瞄配置
环境配置NLog(“NLog.config”);
loggerFactory.AddNLog();
app.AddNLogWeb();
//注册目标
Target.Register(“MyEFTarget”);
//以编程方式添加目标+规则
var target=serviceProvider.GetService();
var规则=新的日志规则(“*”,LogLevel.Info,target);
LogManager.Configuration.AddTarget(“MyEFTarget”,target);//问题就在这里********
LogManager.Configuration.LoggingRules.Add(规则);
LogManager.ReconfigeExistingLoggers();
//……等等
}
问题是NLog会在应用程序的持续时间内缓存目标
实例……我想是吧?所以基本上是单身。它保留了对我的EF上下文的引用,这可能会被处理掉
有更好的办法吗
为了一般性地重申该问题(因为它不是EF问题),“在加载NLog配置时,如何注册/添加具有短期依赖关系的自定义目标”,NLog将使用
ConfigurationItemFactory.Default.CreateInstance
创建目标的实例,并且仅在重新加载配置时才会重新创建目标
如果您每次都需要一个新的EF上下文,我建议您在
protectedoverride void Write(LogEventInfo logEvent)
中加载EF上下文,您可以创建刷新模式,并在刷新时仅打开DB连接。如果您可以在需要时插入IServiceProvider和它的GetService()
。@JoelHarkes连接由EF处理,我无法控制它。如果您有服务,为什么要使用AddScope.AddDbContext?嗯,这有点棘手。要在其中创建上下文,您需要某种依赖关系。但构造函数注入传递的任何依赖项都将在应用程序的生命周期内被缓存。和以前一样的问题。我想我需要使用服务定位器模式。哎呀!:-)你给了我一个主意,我知道。一旦我弄明白了,我会更新这个问题。谢谢你让我走上正轨。这就是我目前的做法,但要让它正常工作需要付出很多努力。不幸的是,NLog不允许通过lambda/factory添加自定义目标,因此每次都会创建一个新的目标,从而允许目标具有自己的非单例依赖项。不要紧,那是为了让我走上正轨。