简体   繁体   中英

DI with NLog in net-core2.0

I have a little lack of understanding with NLog on net core 2.0 I want to create a class with constructor in my console app.

Bot.cs

public class Bot : IBot
{
    static TelegramBotClient _botClient;
    Microsoft.Extensions.Logging.ILogger<Bot> _logger;

    public Bot(string botToken, WebProxy httpProxy, ILogger<Bot> logger)
    {
        _logger = logger;
        _botClient = new TelegramBotClient(botToken, httpProxy);
        //...
    }
}

and Program.cs

public static async Task Main(string[] args)
{
     //...

    appModel = configuration.GetSection("ApplicationModel").Get<ApplicationModel>();
    var userName = appModel.ProxyConfiguration.UserName;
    var password = appModel.ProxyConfiguration.Password;

    var httpProxy = new WebProxy(appModel.ProxyConfiguration.Url, appModel.ProxyConfiguration.Port)
    {
        Credentials = credentials
    };
    NLog.ILogger Logger = LogManager.GetCurrentClassLogger();
    _botClient = new Bot(appModel.BotConfiguration.BotToken, httpProxy, ???);

    //...
}

What should I do to get the Microsoft.Extensions.Logging.ILogger<Bot> in my Bot class? In Program class I have only NLog.ILogger . What the best practice for "partial" DI? I want to pass string botToken, WebProxy httpProxy to constructor in Bot class, but want ILogger<Bot> logger resolve automatically.

Is it possible?

I have an idea to pass IOptions<ApplicationMode> appSettings to Bot class, but it will be a dirty code, willn't it?

This

NLog.ILogger Logger = LogManager.GetCurrentClassLogger();

returns an object of type NLog.Logger .

Your class, on the other hand, expects a constructor parameter of type Microsoft.Extensions.Logging.ILogger<Bot> . So while both are named ILogger they are actually entirely different types.

One answer would be to change your class to expect NLog.Logger instead of Microsoft.Extensions.Logging.ILogger<Bot> . Then you could do this:

NLog.ILogger logger = LogManager.GetCurrentClassLogger();
_botClient = new Bot(appModel.BotConfiguration.BotToken, httpProxy, logger);

That would probably work. The only minor concern I have there is that it makes your Bot class depend on NLog. Right now it depends on a framework abstraction, which is better because it means you can use NLog or substitute some other logger.

So to keep it as-is, you would need to create a class that adapts NLog.ILogger to Microsoft.Extensions.Logging.ILogger<Bot> .

(When I got to this point I started writing the adapter myself. That's when it occurred to me that it almost certainly already existed.)

Fortunately, NLog has already done this in NLog.Extensions.Logging which you an add as a NuGet package. It makes perfect sense that they would provide this, as not everyone who wants to use NLog wants to put NLog-specific types in every class that needs a logger.

They provide documentation on how to configure this in a console app.


I started with this:

public class NLogger : ILogger
{
    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        throw new NotImplementedException();
    }

    public bool IsEnabled(LogLevel logLevel)
    {
        throw new NotImplementedException();
    }

    public IDisposable BeginScope<TState>(TState state)
    {
        throw new NotImplementedException();
    }
}

...and wondered what the implementation would look like. As it turns out, it looks like this: https://github.com/NLog/NLog.Extensions.Logging/blob/master/src/NLog.Extensions.Logging/Logging/NLogLogger.cs .

I was mistaken if I thought I was going to come up with that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM