Doug Wilson
Doug Wilson

Reputation: 353

NLog works in ASP.NET Core App but not in .NET Core xUnit Test Project

I've created a .NET Core class library that defines utility class interfaces and that implements each interface for things like database access via ADO.NET, etc.

Each implementation class utilizes NLog. This works great in an ASP.NET Core Web application that includes and references the .NET Core class library.

However, when I try to instantiate these same implementation classes in the context of a .NET Core xUnit Test project, I get

Unable to cast object of type 'NLog.Logger' to type 'Microsoft.Extensions.Logging.ILogger'

I've searched for similar issues but found none.

In each class I've declared a private readonly variable:

private readonly ILogger<DatabasePersistenceAdoDotNet> _logger = null;

And I'm instantiating this variable like this:

_logger = (ILogger<DatabasePersistenceAdoDotNet>)NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();

This works in an ASP.NET Core Web application that includes and references the .NET Core class library but blows up in my .NET Core xUnit Test project.

I suspect that this has something to do with ASP.NET's dependency inject not being available in the .NET Core xUnit Test project, but I can't figure out how to make my utility package work correctly in both contexts.

Upvotes: 1

Views: 1998

Answers (1)

Julian
Julian

Reputation: 36730

When using NLog with ASP.NET Core, there are two styles:

  1. The non-DI style, with usage of GetCurrentClassLogger()
  2. The DI style, which needs the NLog.Extensions.Logging / NLog.Web.AspNetCore package to bridge between NLog and Microsoft.Extensions.Logging.

When using .GetCurrentClassLogger(), you wil get a NLog logger object (which implements NLog.ILogger, not Microsoft.Extensions.Logging.ILogger).

So if you need a Microsoft.Extensions.Logging.ILogger, you can't use the .GetCurrentClassLogger(). You need to:

  1. Set up the whole DI system yourself and constructor inject the Microsoft.Extensions.Logging.ILogger, or
  2. Use the classes of the NLog.Extensions.Logging package.

Option 2 is the easy way and I will show you how:

// Load NLog
NLog.Web.NLogBuilder.ConfigureNLog("nlog.config");

// Create provider to bridge Microsoft.Extensions.Logging
var provider = new NLog.Extensions.Logging.NLogLoggerProvider();

// Create logger
Microsoft.Extensions.Logging.ILogger logger = provider.CreateLogger(typeof(MyClass).FullName);

Please note, you can't create a Microsoft.Extensions.Logging.ILogger<MyClass> this way! Just a non-generic Microsoft.Extensions.Logging.ILogger. If you need the generic version, then you need the DI setup and that will handle the conversion between both.

NLog.config and test projects

Also good to know, finding a nlog.config in a test project is hard, as unit test frameworks will move the binaries etc. I would recommend to use the config API

e.g.

var configuration = new LoggingConfiguration();
configuration.AddRuleForAllLevels(new ConsoleTarget());
LogManager.Configuration = configuration;

OR

var configuration = XmlLoggingConfiguration.CreateFromXmlString("<nlog>....</nlog>"); //full nlog.config as string
LogManager.Configuration = configuration;

Upvotes: 5

Related Questions