Skip to content

Dependency injection with NLog

Rolf Kristensen edited this page Oct 25, 2023 · 26 revisions

Resolve Dependency Injection Interface during initialization

NLog 5.0 makes it possible to resolve interfaces using dependency injection during initialization. This allows you to load targets using NLog config file, before dependency injection provider is available.

The custom NLog target can then override InitializeTarget to resolve the necessary dependencies:

protected override void InitializeTarget()
{
   var wantedDependency = base.ResolveService<IWantedDependency>();
   base.InitializeTarget();
}

If the custom NLog target requests a dependency, that is unavailable, then NLog will perform re-initialization of the NLog when the dependency becomes available. Service interfaces can registered like this:

NLog.LogManager.Setup().SetupExtensions(ext => RegisterSingletonService<IWantedDependency>(wantedInstance));

It is also possible to connect with an external IServiceProvider for resolving dependencies:

NLog.LogManager.Setup().SetupExtensions(ext => RegisterServiceProvider(serviceProvider));

It is recommended to setup dependency-injection early before loading the NLog LoggingConfiguration, or else they might not take effect.

Resolve Dependency Injection Interface during object creation

NLog v5.2 introduces the ability to register extensions together with custom factory-method:

NLog.LogManager.Setup().SetupExtensions(ext => RegisterTarget<MyTarget>(() => new MyTarget(wantedDependency));

⚠️ NLog v5.2 has marked CreateInstance as obsolete, as it doesn't work well with Ahead-of-Time (AOT) application trimming in .NET

NLog allows one to override the default method for creating new objects when loading configuration from NLog.config.

ConfigurationItemFactory.Default.CreateInstance // namespace NLog.Config

NLog will only be able to create objects of known types. To support custom objects one must also register the config-item-type before it will be recognized. See also Register your custom component

NLog will by default use the default constructor for creating new objects. But one can override the creation like this:

using NLog.Config;

var defaultConstructor = ConfigurationItemFactory.Default.CreateInstance;

ConfigurationItemFactory.Default.CreateInstance.CreateInstance = type =>
{
   if (type == typeof(MyCustomTarget))
       return new MyCustomTarget(myCustomParameter);
   
   return defaultConstructor(type);
};

Initialize NLog configuration with Dependency Injection Provider

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:

  • Default Constructor that initializes an object in disabled state (Ignored by dependency injection provider).
  • Specialized Constructor that initializes an object in working state.

Alternative override the CreateInstance-method as first thing (Before creating first Logger-object or loading NLog config). Where it calls 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 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.

using NLog;

LogManager.Configuration = LogManager.Configuration.Reload();

See also Reinitialize NLog configuration

Clone this wiki locally