使用日志注入模块时,在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)))) .AsImplemen‌​tedInterfaces(); 

其他选项是让Autofac为您创建实例,因此将注册更改为:

  builder.RegisterType() .AsImplemen‌​tedInterfaces(); 

在这种情况下,Autofac将为您处理实例创建,它将调用模块的OnComponentPreparing方法。

如果要提供其他构造函数参数 ,可以使用WithParameterWithParameters方法:

  builder.RegisterType() .AsImplemen‌​tedInterfaces() .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。