我正在使用Nlog
作为IoC容器在Web API项目中使用Unity
作为日志框架。
我有LoggingService
类,该类将类名称作为参数并返回NLog的实例。为此,我使用了依赖注入。
问题:我很困惑如何将类名传递给我的LoggingService
类?
代码:
using NLog;
namespace Portal.Util.Logging
{
public class LoggingService : ILoggingService
{
private readonly ILogger _logger;
public LoggingService(string currentClassName)
{
_logger = LogManager.GetLogger(currentClassName);
}
public void FirstLevelServiceLog(string log)
{
_logger.Log(LogLevel.Debug, log);
}
}
public interface ILoggingService
{
void FirstLevelServiceLog(string log);
}
}
服务层:(正在从控制器中调用)
public class MyService : IMyService
{
private readonly ILoggingService _loggingService;
public MyService(ILoggingService loggingService)
{
_loggingService = loggingService
}
public DoSomething()
{
_loggingService.FirstLevelServiceLog("Debug");
}
}
团结:
var container = new UnityContainer();
container.RegisterType<ILoggingService, LoggingService>(new InjectionConstructor(""))
/* Not sure on how to pass the class name here? */
答案 0 :(得分:3)
这看起来像是掩盖在XY problem后面的设计问题。
日志记录服务需要进行一些重构,以使其更易于注入所需的行为。
引入一个从基础ILoggingService
派生的附加通用接口
public interface ILoggingService<TType> : ILoggingService {
}
public interface ILoggingService {
void FirstLevelServiceLog(string log);
}
重构当前实现以依赖于服务的通用版本
public class LoggingService<TType> : ILoggingService<TType> {
private readonly ILogger _logger;
public LoggingService() {
string currentClassName = typeof(TType).Name;
_logger = LogManager.GetLogger(currentClassName);
}
public void FirstLevelServiceLog(string log) {
_logger.Log(LogLevel.Debug, log);
}
}
这将允许使用type参数来确定日志管理器的类的名称
现在,那些依赖于日志记录服务的人可以通过构造函数注入来明确了解其依赖关系
public class MyService : IMyService {
private readonly ILoggingService _loggingService;
public MyService(ILoggingService<MyService> loggingService) {
_loggingService = loggingService
}
public DoSomething() {
_loggingService.FirstLevelServiceLog("Debug");
}
}
请注意,唯一需要重构的是构造函数的通用参数,因为通用记录器是从基础ILoggingService
派生的。
最终可以使用开放式泛型来注册日志记录服务抽象
var container = new UnityContainer();
container.RegisterType(typeof(ILoggingService<>), typeof(LoggingService<>));
这样,无需为系统中使用的每个记录器注册单独的实现。
答案 1 :(得分:0)
一种方法是使用“按名称注册”。
您首先注册所有记录器,并为每个记录器命名。
您使用InjectionConstructor
来注入参数值。
var ctr = new UnityContainer();
// You can add lifetimemanagers as well
ctr.RegisterType<ILoggingService, LoggingService>("Class1Logger",new InjectionConstructor("Class1"));
ctr.RegisterType<ILoggingService, LoggingService>("Class2Logger", new InjectionConstructor("Class2"));
然后,通过按名称注入(使用Dependency
属性)来创建逻辑类:
public class MyLogic1
{
public MyLogic1([Dependency("Class1Logger")]ILoggingService logger)
{
}
}
public class MyLogic2
{
public MyLogic2([Dependency("Class2Logger")]ILoggingService logger)
{
}
}
这就是您要做的全部。
我通常认为按名称注册并不是真正的最佳实践,而且我大部分时间更喜欢某种虚拟接口继承(因为我不喜欢将相同的接口类型映射到具体类型)。 但是在这种情况下,它似乎是解决问题的一种体面且干净的方法。
如果要自动注册,可以使用某种反射(自定义属性或基于ILogger
的实现)并自动注册所有实例。