NLog.Web: Could not create instance of custom target (when using dependency injection)
I have an ASP.NET Core 2.0 web application. In the Main
method of the app, when I build WebHostBuilder
I use .UseNLog()
method to enable NLog (after .UseStartup
but I’ve tested it also whe .UseNLog()
was before .UseStartup
).
I have the following custom target:
[Target("RemoteNLogTarget")]
public class RemoteNLogTarget : TargetWithLayout
{
protected ILogStorage LogStorage;
public RemoteNLogTarget(ILogStorage logStorage)
{
LogStorage = logStorage;
}
protected override void Write(LogEventInfo logEvent)
{
LogStorage.Store(Layout.Render(logEvent));
}
}
ILogStorage
is the following:
public interface ILogStorage
{
void Store(string logMessage);
}
I have implementation of ILogStorage
it registered in services (as scoped) in my Startup
.
In Startup.Configure
method I have the following code, which should enable me to use custom targets with dependency injection as per: https://stackoverflow.com/a/42101946/1955346
var builtInProvider = ConfigurationItemFactory.Default.CreateInstance;
ConfigurationItemFactory.Default.CreateInstance = type =>
{
return serviceProvider.GetService(type) ?? builtInProvider(type);
};
Target.Register<RemoteNLogTarget>("RemoteNLogTarget");
Finally, my nlog.config
:
<extensions>
<add assembly="MyAssembly"/>
</extensions>
<targets>
<target xsi:type="RemoteNLogTarget" name="RemoteNLogTarget"
layout="${pad:fixedLength=True:padding=-5:${uppercase:${level}}} | ${longdate} | ${processtime} | ${logger} | ${message} | ${exception:format=toString,Data}"
/>
</targets>
Regardless of having <extensions>
declared or not, regardless of having Target.Register<>
called or not, I always end up with the exception :
Cannot access the constructor of type: RemoteNLogTarget. Is the required permission granted?
It seems to me like setting CreateInstance
does not work there. Fun fact is that when I initialize my application, my custom DI method is actually called (and obviously returns proper instance of my RemoteNLogTarget
), but the exception is thrown anyway.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 30 (18 by maintainers)
I have made these modifications to my app and it has corrected the internal nlog errors for me. Thanks for the good write up!
@fuzzzerd The combination of dynamic logging configuration and dependency injection can give a catch22. You want to have logging up and running early, but this will fail if dependent on custom objects that requires a dependency injection provider is fully loaded.
The “ugly” work-around to this catch22 is to have two constructors for your custom-objects:
Alternative override the CreateInstance-method as first thing (Before creating first Logger-object or loading NLog config). To call the specialized constructor with parameters that signals that it should be in disabled state.
Then one can “just” perform a reload of the NLog config, after the the dependency injection provider has been fully loaded and performed final override of
CreateInstance
. This will make NLog recreate all configuration items once again, and now with a working dependency injection provider that calls the specialized constructor with correct parameters.Also created a wiki-page: https://github.com/NLog/NLog/wiki/Dependency-injection-with-NLog
@304NotModified still having errors logged. I’m not 100% confident its a bug in NLog, as it could be that I’m not doing something correctly.
My problem appears to be related to the fact that I have a custom Target defined in my nlog.config and when I call
.UseNLog()
in program.cs main method it loads that configuration file and the target is not registered yet.If I move my call of
NLog.Targets.Target.Register("NLogCustomTarget", typeof(NLogCustomTarget)); // register our custom target
ahead of the
.UseNLog()
call I get the same error OP has here, that the constructor is not accessible, presumably because I am injecting dependencies into the target constructor so it knows where/how to write log entries.If there is a better/different way to register custom targets with dependency injection I’d love to learn more about it.
Like I said, what I have does work in the sense my target is called and can write log data, but it causes an internal nlog error as well as asp.net core sdtout errors on startup.