我们已经在门面和工厂后面抽象了NLog的使用。我们的工厂返回一个NLogFacade实例,它或多或少地包装了一个NLog记录器。我们为工厂和记录器外观都有自己的接口,因此我们可以通过DI注册它们并在测试中模拟它们。工厂有一个通用的非泛型方法来创建ILogger
,而ILogger
接口存在于非泛型和通用的风格中。
public interface ILogFactory
{
ILogger GetLogger(string name);
ILogger GetLogger<TCallingType>();
}
public interface ILogger<TOwner> : ILogger { }
public interface ILogger
{
// This is set as typeof(T).FullName if ILogger<T> is used
// or if ILogFactory.GetLogger<T>() is used.
string Name { get; }
void Trace(string message, [CallerMemberName] string methodName = "");
void Info(string message, [CallerMemberName] string methodName = "");
void Error(string message, [CallerMemberName] string methodName = "");
void Error(string message, Exception exception, [CallerMemberName] string methodName = "");
void Error(Exception exception, [CallerMemberName] string methodName = "");
void Fatal(string message, [CallerMemberName] string methodName = "");
void Fatal(string message, Exception exception, [CallerMemberName] string methodName = "");
void Fatal(Exception exception, [CallerMemberName] string methodName = "");
void Log(LogLevel level, string message, [CallerMemberName] string methodName = "");
void Log(LogLevel level, string message, Exception exception, [CallerMemberName] string methodName = "");
}
目前,我正在使用autofac注册我们的日志工厂,并将其注入我的构造函数。
builder.Register(context => LogService.GetInstance().LogFactory).As<ILogFactory>();
我无法访问ILogFactory
或ILogger
的实施。它们都是公司程序集的内部类,其中包含日志记录。
我想做的是注册注册ILogger<T>
。
// Pseudo Registration
builder.Register(context => LogService.GetLogger<>).As<ILogger<>>();
// Construtor
public HomeController(ILogger<HomeController> logger) { }
有没有办法让我这样做,或者可以访问我的服务注入的类型?我可以使用非泛型调用来获取记录器,其中我传递记录器名称并注册非泛型ILogger
。为了使用它,我需要知道正在注入服务的类型。像这样:
builder.Register(context => LogService.GetLogger(context.ResolvingType.FullName))
.As<ILogger>();
当我查看Register
上的ContainerBuilder
方法时,我看不到任何可以让我确定要注入服务类型的内容。我还查看了OnActivating
和OnActivated
,它们没有我需要的任何类型信息。我有办法确定服务的类型吗?或者有更好的方法来解决这个问题吗?
答案 0 :(得分:1)
要注册打开的泛型,不能使用泛型类型的ref参数,因为那些需要在编译时解析。您必须将open generic作为Type
参数传递给方法,而不是类型ref参数。
builder.Register(context => LogService.GetLogger(typeof(Logger<>))).As(typeof(ILogger<>));
当然,这意味着您需要将工厂设计更改为:
public interface ILogFactory
{
ILogger GetLogger(string name);
ILogger GetLogger<TCallingType>(); // Maybe you won't actually need this overload...
ILogger GetLogger(Type type);
}
答案 1 :(得分:0)
我能够通过使用模块(as explained in their docs)解决这个问题,以便在将ILogger
作为参数注入构造函数时解析它。 Preparing
事件让我可以查看参数,并找出我的服务被注入的参数的拥有类型。
internal class LoggingDependencyRegistrationModule : Autofac.Module
{
private static void OnComponentPreparing(object sender, PreparingEventArgs e)
{
e.Parameters = e.Parameters.Union(new[]
{
new ResolvedParameter(
(p, i) => p.ParameterType == typeof(ILogger),
(p, i) => LogService.GetLogger(p.Member.DeclaringType.FullName)),
});
}
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
// Handle constructor parameters.
registration.Preparing += OnComponentPreparing;
}
}
然后在我的DI设置中,我注册了模块。
builder.RegisterModule(new LoggingDependencyRegistrationModule());
最后我可以将记录器注入我的构造函数
public HomeController(ILogger logger)
{
// This correctly equals MyNamespace.Controllers.HomeController.
string controllerName = logger.Name;
}