问题
I've got a .Net core web app that I'm trying to add logging to via NLog. In previous projects, I've just used something like the following at the top of every class:
private static Logger logger = LogManager.GetCurrentClassLogger();
I've trying to follow more best practices with this project where possible.
My question is, how can I inject a logger which has the fully qualified name of the class that it's being injected into?
In my startup.cs file, so far I've got the following:
services.AddScoped<BLL.Logging.NLogLogger>();
At the moment, the NLogLogger
class creates an instance of an NLog Logger via GetCurrentClassLogger()
, which when used will only ever report the name as "BLL.Logging.NLogLogger" rather than the actual class that the logger is being injected into.
To simplify the question and make it a big more generic: How can you pass in the name of the class that .Net Core is going to inject a class into?
I've thought about something like the below, but not sure how to achieve it:
services.AddScoped<BLL.Logging.NLogLogger>(serviceProvider => new BLL.Logging.NLogLogger("class name here"));
回答1:
Using DI specify ILogger<T>
type instead of Logger
, where T
is the class type that uses the logger, so NLog will know about the class. For example:
public class TodoController : Controller
{
private readonly ILogger _logger;
public TodoController(ILogger<TodoController> logger)
{
_logger = logger;
}
}
回答2:
I think I've figured out an acceptable solution, although not exactly the way I asked the question.
First of all, I create a "LoggerFactory", which has a single method called "GetLogger" (which creates the concrete NLog Logger and accepts a class name as a parameter), and I inject this factory instead of the logger directly.
LoggerFactory:
public class LoggerFactory : ILoggerFactory
{
public ILogger GetLogger(string fullyQualifiedClassName)
{
return new NLogLogger(fullyQualifiedClassName);
}
}
NLogLogger:
public class NLogLogger : ILogger, INLogLogger
{
NLog.Logger mylogger;
public NLogLogger(string fullyQualifiedClassName)
{
mylogger = NLog.LogManager.GetLogger(fullyQualifiedClassName);
}
}
Startup.cs:
services.AddScoped<BLL.Logging.ILoggerFactory>();
The in my controller class, I've got:
private BLL.Logging.ILogger logger;//my NLogLogger inherits this interface
public HomeController(BLL.Logging.ILoggerFactory loggerFactory)
{
logger = loggerFactory.GetLogger(this.GetType().FullName);
}
So what I've effectively now done, is rather than injecting the actual Logger itself (Which @Steven indicated would not be possible the way I was trying to do it), I've instead injected the utility to create an instance of a logger which wraps NLog.
I've still got the responsibility to create the logger within the class, but at least I've decoupled from the underlying logging framework (NLog).
来源:https://stackoverflow.com/questions/41534253/dependency-injection-with-nlog