我在Autofac容器中注册了ILoggerFactory
实现。我希望能够使用Autofac注册以下类并能够实例化它:
public class Test
{
public Test(ILogger<Test> logger)
{
logger.LogInformation("Works!");
}
}
为此,我需要能够“教导”Autofac为任何类ILogger<T>
生成实现T
的实例。有一个ILoggerFactory
扩展方法CreateLogger<T>()
和CreateLogger(Type)
能够生成所需类型的实例,但我无法理解如何让Autofac调用它们。
如果我想要非通用ILogger
,我会写
containerBuilder.Register(c => c.Resolve<ILoggerFactory>().CreateLogger("default"))
但是我不知道如何为通用的做什么。有什么指针吗?
更新:在阅读了更多documentation后,我想出了这个:
public class LoggingModule: Autofac.Module
{
private readonly MethodInfo mi;
public LoggingModule()
{
this.mi = typeof(LoggerFactoryExtensions)
.GetMethod(nameof(LoggerFactoryExtensions.CreateLogger), new[] { typeof(ILoggerFactory) });
}
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
registration.Preparing += OnComponentPreparing;
}
private void OnComponentPreparing(object sender, PreparingEventArgs e)
{
e.Parameters = e.Parameters.Union(
new[]
{
new ResolvedParameter(
(p, i) => IsGenericLoggerParameter(p.ParameterType),
(p, i) => CreateLogger(this.mi, p.ParameterType, i.Resolve<ILoggerFactory>())
)
});
}
private static bool IsGenericLoggerParameter(Type parameterType)
{
return parameterType.IsGenericType && parameterType.GetGenericTypeDefinition() == typeof(ILogger<>);
}
private static object CreateLogger(MethodInfo mi, Type typeArg, ILoggerFactory loggerFactory)
{
Type genericArg = typeArg.GetGenericArguments().First();
MethodInfo generic = mi.MakeGenericMethod(new[] { genericArg });
return generic.Invoke(null, new[] { loggerFactory });
}
}
然后:
containerBuilder.RegisterType<Test>().AsSelf();
containerBuilder.RegisterModule<LoggingModule>();
var container = containerBuilder.Build();
var test = container.Resolve<Test>();
的工作原理。问题是我不完全理解它是如何工作的(更重要的是它可能会如何破坏),所以我仍然在寻找更优雅和/或可理解的解决方案。
答案 0 :(得分:2)
我找到了一个简单的答案,但仅针对ILogger<T>
包中的Microsoft.Extensions.Logging
:使用ServiceCollection
包中的Microsoft.Extensions.DependencyInjection
:
IServiceCollection services = new ServiceCollection();
services.AddLogging(); // all the magic happens here
// set up other services
var builder = new ContainerBuilder();
builder.Populate(services); // from the Autofac.Extensions.DependencyInjection package
IContainer container = builder.Build();
Test t = container.Resolve<Test>();
答案 1 :(得分:1)
我在一年后回答为 AutoFac v6 提供干净的解决方案
将 ILogger Logger 解决方案 至于问题的字面答案:我建议使用 RegisterGeneric 方法。 示例static ContainerBuilder CreateBuilder()
{
var builder = new ContainerBuilder();
builder.RegisterInstance(LoggerFactory.Create(config => config
.AddConsole()
.SetMinimumLevel(LogLevel.Trace)
));
builder.RegisterGeneric(typeof(Logger<>)).As(typeof(ILogger<>));
return builder;
}
如果要注册具有复杂构造函数逻辑的通用服务...
builder.RegisterGeneric((context, types) =>
{
var factory = context.Resolve<ILoggerFactory>();
return factory.CreateLogger(types[0].FullName);
}).As(typeof(ILogger<>));
答案 2 :(得分:0)
是的,很高兴您发布了此信息: 在您的示例中,我将其用于ILogger和ILogger
public class LoggingDependencyRegistrationModule : Autofac.Module
{
private readonly ILoggerFactory _lf;
private readonly MethodInfo _mi;
private readonly Type _t;
public LoggingDependencyRegistrationModule(ILoggerFactory lf)
{
_lf = lf;
_mi = typeof(LoggerFactoryExtensions).GetMethod(nameof(LoggerFactoryExtensions.CreateLogger), new[] { typeof(ILoggerFactory) });
_t = typeof(ILogger);
}
private void OnComponentPreparing(object sender, PreparingEventArgs e)
{
var t = e.Component.Activator.LimitType;
e.Parameters = e.Parameters.Union(new[]
{
new ResolvedParameter(
(p, i) =>
_t.IsAssignableFrom(p.ParameterType),
(p,i)=>{
if(p.ParameterType == _t)
return _lf.CreateLogger(t.ToString());
return CreateLogger(_mi, p.ParameterType, _lf);
}
)
});
}
private static object CreateLogger(MethodInfo mi, Type typeArg, ILoggerFactory loggerFactory)
{
Type genericArg = typeArg.GetGenericArguments().First();
MethodInfo generic = mi.MakeGenericMethod(new[] { genericArg });
return generic.Invoke(null, new[] { loggerFactory });
}
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
registration.Preparing += OnComponentPreparing;
}
protected override void Load(ContainerBuilder builder)
{
builder.RegisterInstance(_lf).SingleInstance();
base.Load(builder);
}
}
答案 3 :(得分:0)
使用Autofac并需要将Microsoft ILogger
ContainerBuilder builder = new ContainerBuilder();
var loggerFactory = new LoggerFactory();
//loggerFactory.AddProvider(LogProvider) //If you need another provider than Microsoft logger
builder.RegisterInstance(loggerFactory).As<ILoggerFactory>().SingleInstance();
builder.RegisterGeneric(typeof(Logger<>)).As(typeof(ILogger<>)).SingleInstance();
需要注入ILogger