6

我使用以下代码为所有需要它的类注册 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<ILog>())).AsImplementedInterfaces();

这是那堂课

public class ClassThatNeedsILog
{
    public ClassThatNeedsILog(ILog log)
    {

    }
}

我收到以下异常:

Autofac.Core.Registration.ComponentNotRegisteredException :请求的服务“log4net.ILog”尚未注册。要避免此异常,请注册一个组件以提供服务,使用 IsRegistered() 检查服务注册,或使用 ResolveOptional() 方法解决可选依赖项。

4

3 回答 3

13

LogInjectionModule 永远不会将任何内容注册ILog 到容器中,只会为准备面上已解析的实例提供参数,并且它仅适用于由 Autofac 创建的实例。

因此,当您编写时,builder.Register(x => new ClassThatNeedsILog(x.Resolve<ILog>()))您正在ClassThatNeedsILog手动创建。和new ClassThatNeedsILog(...)

因此 Autofac 不知道您的实例创建(因此您OnComponentPreparing不会运行),并且因为您还没有真正注册任何ILog实现,所以您获得了ComponentNotRegisteredException.

你有两个选择:

  • ILog直接在容器中注册
  • 让 Autofac 创建您的ClassThatNeedsILog类型。

所以你可以ILog在容器中注册一个:

builder.RegisterInstance(LogManager.GetLogger("Logger")).As<ILog>();

然后你的代码就可以正常工作了。

或者,如果您无论如何ClassThatNeedsILog手动创建可以直接提供ILog那里:

 builder.Register(x => new 
     ClassThatNeedsILog(LogManager.GetLogger(typeof(ClassThatNeedsILog))))
     .AsImplemen‌​tedInterfaces();

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

 builder.RegisterType<ClassThatNeedsILog>()
     .AsImplemen‌​tedInterfaces();

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

如果你想提供额外的构造函数参数,你可以使用WithParameterWithParameters方法:

 builder.RegisterType<ClassThatNeedsILog>()
     .AsImplemen‌​tedInterfaces()
     .WithParameters(new Parameter[] {
         ResolvedParameter.ForNamed<IAnotherInterface>("NAME"),
         ResolvedParameter.ForNamed<IYetAnotherInterface>("ANOTHERNAME")});
于 2013-11-08T06:30:42.930 回答
0

builder需要一个才Build可以。containerResolve

尝试这样的事情(未经测试)

builder
    .RegisterAssemblyTypes(typeof (IResourceFinder).Assembly)
    .AsImplementedInterfaces();
/* process LogInjectionModule */
IContainer container = builder.Build();

var updateBuilder = new ContainerBuilder();
updateBuilder
    .Register(x => new ClassThatNeedsILog(x.Resolve<ILog>()))
    .AsImplementedInterfaces();
updateBuilder.Update(container);
于 2013-11-05T10:41:33.027 回答
0

nemesv 的回答为我解决了这个问题。

不过,在使用 RegisterType 方法后,我不得不花更多时间让它工作,因为我错过了以下内容:

config.Filters.AddRange(config.DependencyResolver.GetServices(typeof(IExceptionFilter)).Select(o => o as IExceptionFilter));

如果其他人忘记配置过滤器,只需在此处添加提及即可。

于 2016-03-13T00:36:40.520 回答