Sto usando l'ultimo NLog, ASP.NET Core, EF Core.
Ho scritto un obiettivo di registro personalizzato che salva tramite EF:
public class MyEFTarget : TargetWithLayout
{
private readonly IMyContext _context;
public MyEFTarget(IMyContext context) : base()
{
_context = context;
}
protected override void Write(LogEventInfo logEvent)
{
// and so on...
}
}
La mia Startup
:
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
}
Il problema è che NLog memorizza nella cache l'istanza di target
per la durata dell'app ... presumo? Quindi è fondamentalmente un singleton. E sta mantenendo un riferimento al mio contesto EF, che potrebbe essere smaltito.
C'è un modo migliore?
Per risolvere genericamente il problema (perché non si tratta di un problema EF), "come faccio a registrare / aggiungere un target personalizzato che ha dipendenze di breve durata"?
Quando viene caricata la configurazione di NLog, NLog creerà un'istanza della destinazione con ConfigurationItemFactory.Default.CreateInstance
e la destinazione verrà ricreata solo durante il ricaricamento della configurazione.
Se hai bisogno di un nuovo contesto EF ogni volta, ti consiglio di caricare il contesto EF in protected override void Write(LogEventInfo logEvent)