Autofac 无法解析类型为“log4net”的服务。ILog'

Autofac Unable to resolve service for type 'log4net.ILog'

提问人:Dark_Knight 提问时间:11/4/2023 最后编辑:Dark_Knight 更新时间:11/6/2023 访问量:59

问:

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

我们使用,我正在得到FluentMigrator

无法解析类型为“log4net”的服务。ILog“,同时尝试 激活“Migrations.Maintenance.BeforeAll.FlushRedisOnVersionUpdate”。

中间件似乎无法解析 log4net。ILog,它注入到构造函数中。

internal class OrderedMaintenanceLoader : IMaintenanceLoader
{
    #region Private fields

    private readonly IMaintenanceLoader _inner;
    private readonly CurrentReleaseMigrationStage _releaseMigrationStage;

    #endregion
    #region Ctors

    public OrderedMaintenanceLoader(IMaintenanceLoader inner, CurrentReleaseMigrationStage releaseMigrationStage)
    {
        _inner = inner ?? throw new ArgumentNullException(nameof(inner));
        _releaseMigrationStage = releaseMigrationStage ?? throw new ArgumentNullException(nameof(releaseMigrationStage));
    }

    #endregion
    #region IMaintenanceLoader Members

    public IList<IMigrationInfo> LoadMaintenance(MigrationStage stage)
    {
        return _inner.LoadMaintenance(stage)
            .Where(info => _releaseMigrationStage.CanExecuteMaintenanceMigration(info.Migration))
            .OrderBy(
                info =>
                {
                    OrderedMaintenanceAttribute orderedMaintenanceAttribute = info.Migration.GetType().GetCustomAttribute<OrderedMaintenanceAttribute>();

                    return orderedMaintenanceAttribute?.Order ?? int.MaxValue;
                })
            .ToList();
    }

    #endregion
}

以下是注册的一部分(有很多注册正在发生):

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

builder.RegisterType<LoggerAdapterProvider>().As<ILoggerProvider>().InstancePerLifetimeScope();
builder.RegisterType<LoggerFactory>().As<ILoggerFactory>().InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Logger<>)).As(typeof(ILogger<>)).InstancePerLifetimeScope();

// registers AutofacServiceProvider and AutofacServiceScopeFactory
builder.Populate(Enumerable.Empty<ServiceDescriptor>());

builder.RegisterType<AssemblyFileLoadEngine>().As<IAssemblyLoadEngine>().InstancePerLifetimeScope();
builder.RegisterType<MaintenanceLoader>();
builder.Register(context => new OrderedMaintenanceLoader(context.Resolve<IMaintenanceLoader>(), context.Resolve<CurrentReleaseMigrationStage>()))
        .As<IMaintenanceLoader>()
        .InstancePerLifetimeScope();
builder
    .RegisterType<AssemblySource>()
    .Keyed<IAssemblySource>(AssemblySourceKey)
    .InstancePerLifetimeScope();

builder
    .Register<IAssemblySource>(
        ctx =>
            new MaintenanceAssemblySource(ctx.ResolveKeyed<IAssemblySource>(AssemblySourceKey)))
    .As<IAssemblySource>()
    .InstancePerLifetimeScope();

这是在构造函数中失败的迁移类:

[OrderedMaintenance(MigrationStage.BeforeAll, 5)]
public class FlushRedisOnVersionUpdate : ConditionalMigration
{
    #region Private fields

    private readonly IConfigurationStateMonitor _configurationStateMonitor;
    private readonly ILog _logger;
    #endregion
    #region Ctors

    public FlushRedisOnVersionUpdate(
        IConfigurationStateMonitor configurationStateMonitor, 
        ILog logger) : base(migrationProcessor)
    {
        _configurationStateMonitor = configurationStateMonitor;
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    #endregion
    #region Overrides

    public override void Up()
    {
        _configurationStateMonitor.FlushCache();
    }

    #endregion
}

这是运行迁移的类:

public class MigrationService : IMigrationService
{
    #region Private fields

    private readonly ILog _logger;
    private readonly DatabaseOptions _databaseOptions;
    private readonly MigrationManagerOptions _migrationOptions;
    private readonly ILifetimeScope _scope;

    #endregion
    #region Ctors

    public MigrationService(
        DatabaseOptions databaseOptions,
        MigrationManagerOptions migrationOptions,
        ILog logger,
        ILifetimeScope scope)
    {
        _databaseOptions = databaseOptions;
        _migrationOptions = migrationOptions;
        _scope = scope;
        _logger = logger;
    }

    #endregion
    #region Private methods

    private ILifetimeScope BeginLifetimeScope(PackageDefinition package, Release release, ReleaseMigrationStage releaseMigrationStage)
    {
        return _scope.BeginLifetimeScope(
            builder =>
            {
                builder
                    .RegisterModule<MicrosoftExtensionsOptionsModule>();

                builder
                    .Configure<ProcessorOptions>(
                        options =>
                        {
                            options.ConnectionString = _databaseOptions.ConnectionString;
                            options.Timeout = TimeSpan.FromMinutes(_migrationOptions.DefaultMigrationCommandTimeout);
                        });
                builder.RegisterInstance(new CurrentReleaseMigrationStage(releaseMigrationStage));

                builder.RegisterInstance(package);
                builder.RegisterInstance(new CurrentRelease(release));
            });
    }

    #endregion
    #region IMigrationService Members

    public bool Migrate(PackageDefinition package, Release release, ReleaseMigrationStage releaseMigrationStage)
    {
        using (ILifetimeScope scope = BeginLifetimeScope(package, release, releaseMigrationStage))
        {
            bool hasAnyToApply = scope.Resolve<TaskExecutor>().HasMigrationsToApply();

            scope.Resolve<IMigrationRunner>().MigrateUp();

            return hasAnyToApply;
        }
    }

    #endregion
}

MigrationService实际上可以得到ILog ...可能是因为我们创建了一个生命周期范围的问题?

更新:

我已经创建了一个单元测试,但没有调用并且仍然失败(所以问题不在创建生命周期范围中):MigrationService

这是例外:

System.Reflection.TargetInvocationException
  HResult=0x80131604
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) in f:\dd\ndp\clr\src\BCL\system\reflection\methodinfo.cs:line 761
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) in f:\dd\ndp\clr\src\BCL\system\reflection\methodinfo.cs:line 739
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) in f:\dd\ndp\clr\src\BCL\system\reflection\methodbase.cs:line 211
   at NUnit.Framework.Internal.Reflect.InvokeMethod(MethodInfo method, Object fixture, Object[] args) in C:\Src\NUnit\nunit\src\NUnitFramework\framework\Internal\Reflect.cs:line 222

  This exception was originally thrown at this call stack:
    Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(System.IServiceProvider) in ActivatorUtilities.cs
    Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(System.IServiceProvider, System.Type, object[]) in ActivatorUtilities.cs
    FluentMigrator.Runner.MaintenanceLoader..ctor.AnonymousMethod__4(<>f__AnonymousType3<System.Type, FluentMigrator.MigrationStage?>)
    System.Linq.Enumerable.WhereSelectEnumerableIterator<TSource, TResult>.MoveNext() in Enumerable.cs
    System.Linq.Lookup<TKey, TElement>.Create<TSource>(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource, TKey>, System.Func<TSource, TElement>, System.Collections.Generic.IEqualityComparer<TKey>) in Lookup.cs
    System.Linq.GroupedEnumerable<TSource, TKey, TElement>.GetEnumerator() in GroupedEnumerable.cs
    System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource, TKey>, System.Func<TSource, TElement>, System.Collections.Generic.IEqualityComparer<TKey>) in Enumerable.cs
    FluentMigrator.Runner.MaintenanceLoader.MaintenanceLoader(FluentMigrator.Runner.Initialization.IAssemblySource, Microsoft.Extensions.Options.IOptions<FluentMigrator.Runner.Initialization.RunnerOptions>, FluentMigrator.Runner.IMigrationRunnerConventions, System.IServiceProvider) in MaintenanceLoader.cs
    Autofac.Core.Activators.Reflection.BoundConstructor.Instantiate() in BoundConstructor.cs

Inner Exception 1:
DependencyResolutionException: An exception was thrown while activating λ:System.Object -> FluentMigrator.Runner.MaintenanceLoader.

Inner Exception 2:
DependencyResolutionException: An exception was thrown while invoking the constructor 'Void .ctor(FluentMigrator.Runner.Initialization.IAssemblySource, Microsoft.Extensions.Options.IOptions`1[FluentMigrator.Runner.Initialization.RunnerOptions], FluentMigrator.Runner.IMigrationRunnerConventions, System.IServiceProvider)' on type 'MaintenanceLoader'.

Inner Exception 3:
InvalidOperationException: Unable to resolve service for type 'log4net.ILog' while attempting to activate 'Migrations.Maintenance.BeforeAll.FlushRedisOnVersionUpdate'.

下面是测试用例:

[TestCase(4, typeof(FlushRedisOnVersionUpdate), Description = "FlushRedisOnVersionUpdate should run after RemoveBuilderEntityPropertiesMigration")]
public void BeforeAllMigrationsShouldRunInSpecifiedOrder(int order, Type expectedMigrationType)
{
    using (IContainer container = BuildContainer())
    {
        IMaintenanceLoader maintenanceLoader = container.Resolve<IMaintenanceLoader>();
        IList<IMigrationInfo> beforeAllMigrations = maintenanceLoader.LoadMaintenance(MigrationStage.BeforeAll);

        Assert.IsNotNull(beforeAllMigrations);
        Assert.Less(order, beforeAllMigrations.Count);
        Assert.IsInstanceOf(expectedMigrationType, beforeAllMigrations[order].Migration);
    }
}

它失败IMaintenanceLoader maintenanceLoader = container.Resolve<IMaintenanceLoader>();

我还更改了注册以使用装饰器注册,但结果相同。

builder.RegisterType<MaintenanceLoader>()
        .Keyed<IMaintenanceLoader>(DecorateWithEx)
        .UsingConstructor(typeof(IAssemblySource),
                            typeof(IOptions<RunnerOptions>),
                            typeof(IMigrationRunnerConventions),
                            typeof(IServiceProvider));

builder
    .RegisterType<OrderedMaintenanceLoader>()
    .As<IOrderedMaintenanceLoader>();

builder
    .RegisterDecorator<IMaintenanceLoader>((ctx, maintenanceLoader) =>
        ctx.Resolve<IOrderedMaintenanceLoader>(TypedParameter.From(maintenanceLoader)), DecorateWithEx)
    .InstancePerLifetimeScope();
C# ASP.NET-MVC Autofac Fluent-Migrator

评论


答:

0赞 Mark Seemann 11/4/2023 #1

这是 OP 中发布的注册码:

builder.RegisterType<LoggerAdapterProvider>().As<ILoggerProvider>().InstancePerLifetimeScope();
builder.RegisterType<LoggerFactory>().As<ILoggerFactory>().InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Logger<>)).As(typeof(ILogger<>)).InstancePerLifetimeScope();

// registers AutofacServiceProvider and AutofacServiceScopeFactory
builder.Populate(Enumerable.Empty<ServiceDescriptor>());

builder.RegisterType<AssemblyFileLoadEngine>().As<IAssemblyLoadEngine>().InstancePerLifetimeScope();
builder.RegisterType<MaintenanceLoader>();
builder.Register(context => new OrderedMaintenanceLoader(context.Resolve<IMaintenanceLoader>(), context.Resolve<CurrentReleaseMigrationStage>()))
       .As<IMaintenanceLoader>()
       .InstancePerLifetimeScope();

这些语句均未注册 。注册服务,或者实现处理它的注册源ILog

评论

0赞 Dark_Knight 11/4/2023
对不起,我忘了提到我向新中间件注册了日志模块。我将编辑问题。它在那里,但仍然抛出异常