为什么Autofac Log4Net中间件不允许我直接解析“ILog”?

Why doesn't Autofac Log4Net middleware allow me to directly resolve `ILog`?

提问人:Dark_Knight 提问时间:10/31/2023 最后编辑:Travis IlligDark_Knight 更新时间:11/1/2023 访问量:57

问:

我有 ASP.NET 运行良好的 MVC 应用程序,但是一旦我升级了 Autofac 并更改了 Log4Net 中间件示例,如果我尝试解决 ILog,它就会不断失败。

代码如下:

    public class Log4NetMiddleware : IResolveMiddleware
    {
        public PipelinePhase Phase => PipelinePhase.ParameterSelection;

        public void Execute(ResolveRequestContext context, Action<ResolveRequestContext> next)
        {
            // Add our parameters.
            context.ChangeParameters(context.Parameters.Union(
                new[]
                {
              new ResolvedParameter(
                  (p, i) => p.ParameterType == typeof(ILog),
                  (p, i) => LogManager.GetLogger(p.Member.DeclaringType)
              ),
                }));

            // Continue the resolve.
            next(context);

            // Has an instance been activated?
            if (context.NewInstanceActivated)
            {
                Type instanceType = context.Instance.GetType();

                // Get all the injectable properties to set.
                // If you wanted to ensure the properties were only UNSET properties,
                // here's where you'd do it.
                IEnumerable<PropertyInfo> properties = instanceType
                    .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                    .Where(p => p.PropertyType == typeof(ILog) && p.CanWrite && p.GetIndexParameters().Length == 0);

                // Set the properties located.
                foreach (PropertyInfo propToSet in properties)
                {
                    propToSet.SetValue(context.Instance, LogManager.GetLogger(instanceType), null);
                }
            }
        }
    }


    public class MiddlewareModule : Autofac.Module
    {
        private readonly IResolveMiddleware middleware;

        public MiddlewareModule(IResolveMiddleware middleware)
        {
            this.middleware = middleware;
        }

        protected override void AttachToComponentRegistration(IComponentRegistryBuilder componentRegistryBuilder, IComponentRegistration registration)
        {
            // Attach to the registration's pipeline build.
            registration.PipelineBuilding += (sender, pipeline) =>
            {
                // Add our middleware to the pipeline.
                pipeline.Use(middleware);
            };
        }
    }

这里是:Global.asax.cs

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            ContainerBuilder builder = new ContainerBuilder();
            var loggerMiddlewareModule = new MiddlewareModule(new Log4NetMiddleware());
            builder.RegisterModule(loggerMiddlewareModule);

            IContainer container = builder.Build();
            ILog log = container.Resolve<ILog>(TypedParameter.From(typeof(MvcApplication)));
        }

尝试解决 ILog 时失败:

请求的服务 log4net.Core.ILogger' 尚未注册。若要避免此异常,请注册组件以提供服务,使用 IsRegistered() 检查服务注册,或使用 ResolveOptional() 方法解析可选依赖项。

有关详细信息,请参阅 https://autofac.rtfd.io/help/service-not-registered。 说明:执行 当前 Web 请求。请查看堆栈跟踪以了解更多信息 有关错误及其在代码中的来源的信息。

异常详细信息: Autofac.Core.Registration.ComponentNotRegisteredException:该 请求的服务“log4net.Core.ILogger' 尚未注册。自 避免此异常,请注册一个组件以提供 service,使用 IsRegistered() 检查服务注册,或使用 ResolveOptional() 方法解析可选依赖项。

有关详细信息,请参阅 https://autofac.rtfd.io/help/service-not-registered

#Autofac 版本 7.1.0

那么我该如何解决呢?ILog

ASP.NET-MVC AUTOFAC 日志4net

评论


答:

2赞 Travis Illig 11/1/2023 #1

我不会只是告诉你答案,而是要引导你了解如何自己弄清楚发生了什么,然后确认答案。所以坚持我。:)

我们所知道的:

  • 您已将 添加到您的应用中。Log4NetMiddleware
  • 您正在尝试直接解析 .ILog

在文档页面上,描述如下:Log4NetMiddleware

下面是示例中间件,它根据要激活的组件的类型注入参数。此示例中间件同时处理构造函数和属性注入。ILog

这应该是一个很大的线索。它的中间件被描述为允许您注入参数。ILog

但是,让我们看一下实际的中间件代码。知道您放入应用程序中的代码的作用总是好的。

我们首先看到的是一个调用 .该块正在向进入解析操作的参数集添加一个参数 - 它正在添加一个基于调用类型的参数。这与执行以下操作相同:context.ChangeParametersILog

container.Resolve<SomethingThatLogs>(
  TypedParameter.From(
    LogManager.GetLogger(typeof(SomethingThatLogs));

如果(在此示例中)的构造函数参数为 ,它将解析。这意味着看起来像......SomethingThatLogsILogSomethingThatLogs

public class SomethingThatLogs
{
  public SomethingThatLogs(ILog logger)
  {
  }
}

所以,这涵盖了构造函数。下一个区块正在进行一些类似的工作,但我们看到有对属性的反射。啊!它将尝试注入 ILog 的属性值。很酷,所以如果看起来像这样......SomethingThatLogs

public class SomethingThatLogs
{
  public ILog Logger { get; set; }
}

...然后模块将找到该属性并为您注入属性。

该中间件模块中还有什么?

技巧问题:什么都没有。

里面没有别的东西。它可以注入构造函数参数或属性值。

让我们再次回过头来,看看你要做什么:你要尝试解析 ILog,而不是尝试使用 ILog 的构造函数或属性来解析某些内容

因此,当异常告诉您未注册时,这是绝对正确的。ILog

如果要直接解析 ILog,则需要注册 ILog

但是,这没有多大价值。如果您像这样直接获得记录器,只需使用调用即可。为什么要通过DI?它没有增加价值。Log4Net 本身对日志记录实例进行各种缓存和管理,而 Autofac 则不处理。LogManager.GetLogger()

评论

0赞 Dark_Knight 11/1/2023
你是对的,起初我只是想升级Autofac,但错误太多了。但后来我开始仔细阅读它,我明白它只是注入构造函数和属性。感谢您引导我深入了解它。
0赞 Dark_Knight 11/3/2023
我现在还有另一个问题需要帮助。我们使用,我得到的似乎是中间件无法解析 log4net。在构造函数中注入的 ILogFluentMigratorUnable to resolve service for type 'log4net.ILog' while attempting to activate 'Migrations.Maintenance.BeforeAll.FlushRedisOnVersionUpdate'.
0赞 Dark_Knight 11/3/2023
public class FlushRedisOnVersionUpdate : ForwardOnlyMigration { private readonly ILog _logger; public FlushRedisOnVersionUpdate( ILog logger) : base(migrationProcessor) { _logger = logger; } }
0赞 Travis Illig 11/4/2023
我建议提出一个新问题,并包括一个最小的可重复示例。StackOverflow 并不是真正为迭代一组不断发展的问题而设置的。或者,如果您需要更多交互式帮助,codereview.stackexchange.com 是一个检查的好地方。不幸的是,虽然我尽我所能帮助人们,但我没有空闲的咨询时间来真正挖掘每个人遇到的每一个问题。我希望我真的有这样的时间。不好意思。
0赞 Dark_Knight 11/4/2023
谢谢,我创建了一个新问题 stackoverflow.com/questions/77420066/...