使用日志注入模块时,在Autofac中显式解析ILog
我使用以下代码为所有需要它的类注册log4net。
public class LogInjectionModule : Module { private readonly string _configPath; public LogInjectionModule(string configPath) { _configPath = configPath; } protected override void AttachToComponentRegistration(IComponentRegistry registry, IComponentRegistration registration) { XmlConfigurator.Configure(new FileInfo(_configPath)); registration.Preparing += OnComponentPreparing; } private static void OnComponentPreparing(object sender, PreparingEventArgs e) { var t = e.Component.Activator.LimitType; e.Parameters = e.Parameters.Union(new[] { new ResolvedParameter((p, i) => p.ParameterType == typeof (ILog), (p, i) => LogManager.GetLogger(t)) }); } }
使用autofac的类型扫描注册所有类:
builder.RegisterAssemblyTypes(typeof (IResourceFinder).Assembly) .AsImplementedInterfaces();
它工作正常!
需要明确注册一个类尝试解决ILog并失败
builder.Register(x => new ClassThatNeedsILog(x.Resolve())).AsImplementedInterfaces();
这是上课
public class ClassThatNeedsILog { public ClassThatNeedsILog(ILog log) { } }
我收到以下exception:
Autofac.Core.Registration.ComponentNotRegisteredException:请求的服务’log4net.ILog’尚未注册。 要避免此exception,请注册组件以提供服务,使用IsRegistered()检查服务注册,或使用ResolveOptional()方法解析可选的依赖项。
您的LogInjectionModule
永远不会将任何ILog
注册到容器中,只为准备面上的已解析实例提供参数,并且它仅适用于Autofac创建的实例。
因此,当您编写builder.Register(x => new ClassThatNeedsILog(x.Resolve
您将手动创建ClassThatNeedsILog
。 使用new ClassThatNeedsILog(...)
因此,Autofac不知道您的实例创建(因此您的OnComponentPreparing
将不会运行),并且因为您没有真正注册任何ILog
实现,您将获得ComponentNotRegisteredException
。
你有两个选择:
- 直接在容器中注册
ILog
- 让Autofac创建
ClassThatNeedsILog
类型。
所以你可以在容器中注册一个ILog
:
builder.RegisterInstance(LogManager.GetLogger("Logger")).As();
然后你的代码将正常工作。
或者,无论如何你手动创建ClassThatNeedsILog
可以直接提供ILog
:
builder.Register(x => new ClassThatNeedsILog(LogManager.GetLogger(typeof(ClassThatNeedsILog)))) .AsImplementedInterfaces();
其他选项是让Autofac为您创建实例,因此将注册更改为:
builder.RegisterType() .AsImplementedInterfaces();
在这种情况下,Autofac将为您处理实例创建,它将调用模块的OnComponentPreparing
方法。
如果要提供其他构造函数参数 ,可以使用WithParameter
和WithParameters
方法:
builder.RegisterType() .AsImplementedInterfaces() .WithParameters(new Parameter[] { ResolvedParameter.ForNamed("NAME"), ResolvedParameter.ForNamed("ANOTHERNAME")});
builder
需要在可以Resolve
之前Build
container
。
尝试这样的事情(未经测试)
builder .RegisterAssemblyTypes(typeof (IResourceFinder).Assembly) .AsImplementedInterfaces(); /* process LogInjectionModule */ IContainer container = builder.Build(); var updateBuilder = new ContainerBuilder(); updateBuilder .Register(x => new ClassThatNeedsILog(x.Resolve())) .AsImplementedInterfaces(); updateBuilder.Update(container);
nemesv的回答为我解决了这个问题。
虽然,在使用RegisterType方法之后我不得不花费更多的时间来使用它,因为我错过了以下内容:
config.Filters.AddRange(config.DependencyResolver.GetServices(typeof(IExceptionFilter)).Select(o => o as IExceptionFilter));
只是在这里添加它,如果其他人忘记了首先配置filter。