提问人:Dark_Knight 提问时间:10/31/2023 最后编辑:Travis IlligDark_Knight 更新时间:11/1/2023 访问量:57
为什么Autofac Log4Net中间件不允许我直接解析“ILog”?
Why doesn't Autofac Log4Net middleware allow me to directly resolve `ILog`?
问:
我有 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
答:
我不会只是告诉你答案,而是要引导你了解如何自己弄清楚发生了什么,然后确认答案。所以坚持我。:)
我们所知道的:
- 您已将 添加到您的应用中。
Log4NetMiddleware
- 您正在尝试直接解析 .
ILog
在文档页面上,描述如下:Log4NetMiddleware
下面是示例中间件,它根据要激活的组件的类型注入参数。此示例中间件同时处理构造函数和属性注入。
ILog
这应该是一个很大的线索。它的中间件被描述为允许您注入参数。ILog
但是,让我们看一下实际的中间件代码。知道您放入应用程序中的代码的作用总是好的。
我们首先看到的是一个调用 .该块正在向进入解析操作的参数集添加一个参数 - 它正在添加一个基于调用类型的参数。这与执行以下操作相同:context.ChangeParameters
ILog
container.Resolve<SomethingThatLogs>(
TypedParameter.From(
LogManager.GetLogger(typeof(SomethingThatLogs));
如果(在此示例中)的构造函数参数为 ,它将解析。这意味着看起来像......SomethingThatLogs
ILog
SomethingThatLogs
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()
评论
FluentMigrator
Unable to resolve service for type 'log4net.ILog' while attempting to activate 'Migrations.Maintenance.BeforeAll.FlushRedisOnVersionUpdate'.
public class FlushRedisOnVersionUpdate : ForwardOnlyMigration { private readonly ILog _logger; public FlushRedisOnVersionUpdate( ILog logger) : base(migrationProcessor) { _logger = logger; } }
评论