закрытая регистрация универсального типа - Autofac - не может разрешить параметр x конструктора - PullRequest
0 голосов
/ 18 сентября 2018

Я получаю следующее исключение:

"Ни один из конструкторов не найден с 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' для типа 'NetCore.DAL.EF.Repositories.Core.Common.SystemSettingRepository 'можно вызвать с доступными службами и параметрами: \ r \ nНе разрешить параметр' NetCore.DAL.EF.DatabaseFactory 1[NetCore.DAL.EF.AppDbContext] databaseFactory' of constructor 'Void .ctor(NetCore.DAL.EF.DatabaseFactory 1 [NetCore.DAL.EF.AppDbContext]) '. "

Вот информация о регистрации Autofac для SystemSettingRepository:

autofacServiceProvider.Non-Public members._lifetimeScope.ComponentRegistry.Registrations [28] = {Activator = SystemSettingRepository (ReflectionActivator), Services = [Dcs.NetCore.ApplicationCore.BLL.Domain.Features.Common.SystemSettings.ISystemSettingRepository, Dcs.NetCore.Infrastructure.Common.IRepository`1 [[Dcs.NetCore.ApplicationCore.BLL.Domain.Entities.Common.SystemSetting.ApplicationCore.BLL, версия = 1.0.0.0, культура = нейтральная, PublicKeyToken = ноль]], NetCore.DAL.EF.Repositories.Core.Common.SystemSettingRepository], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = Нет, Ownership = OwnedByLifetimeScope}

autofacServiceProvider.Non-Public members._lifetimeScope.ComponentRegistryTarget.Services [0] .ServiceType = {Dcs.NetCore.ApplicationCore.BLL.Domain.Features.Common.SystemSettings.ISystemSettingRepository}

autofacServiceProvider.Non-Public members._pontimeReg.28]. Target.Services [1] .ServiceType = {Dcs.NetCore.Infrastructure.Common.IRepository`1 [Dcs.NetCore.ApplicationCore.BLL.Domain.Entities.Common.SystemSetting]}

autofacServiceProvider.Non-Public members._lifetimeScope.ComponentRegistry.Registrations [28]. Target.Services [2] .ServiceType = {NetCore.DAL.EF.Repositories.Core.Common.SystemSettingReposit

Как видите, сервисы зарегистрированы.Однако для параметра databaseFactory это не так.Вот мой код:

public class Startup
{
    …
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        …
        return AutofacBuilder();
    }

    private AutofacServiceProvider AutofacBuilder()
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule<AutofacModule_AspNetCore>();
        builder.Populate(_services);
        this.AutofacContainer = builder.Build();
        var autofacServiceProvider = new AutofacServiceProvider(this.AutofacContainer);
        return autofacServiceProvider;
    }
}

public class AutofacModule_AspNetCore : Autofac.Module
{
    protected override void Load(ContainerBuilder builder)
    {
            RegisterDbContexts();
            RegisterComponents();
    }
    private void RegisterComponents()
    {
        _builder.RegisterGeneric(typeof(DatabaseFactory<>))
            .As(typeof(IDatabaseFactory<>))
            .InstancePerDependency();
        _builder.RegisterAssemblyTypes(_assembly)
            .AsClosedTypesOf(typeof(IRepository<>))
            .WithParameter(new ResolvedParameter((p, i) => p.Name == "databaseFactory",
                                                 (p, i) => i.Resolve<DatabaseFactory<AppDbContext>>()))
            //.WithParameter("databaseFactory", new DatabaseFactory<AppDbContext>())
            //.WithParameter(ResolvedParameter//.ForNamed<IDbContext>("coreDomainDbContext"));
            //.WithParameter("databaseFactory", )
            .InstancePerDependency();
    }
    private void RegisterDbContexts()
    {
        RegisterAppDbContextInstance();
    }

    private void RegisterAppDbContextInstance()
    {
        // register DbContextOptionsBuilderHelper
        _builder.RegisterType<AppDbContextOptionsBuilderHelper>()
            .InstancePerDependency();
        // configure DbContextOptions
        var dbContextOptionsBuilderHelper = new AppDbContextOptionsBuilderHelper();
        var dbContextOptionsBuilder = dbContextOptionsBuilderHelper.GetDbContextOptionsBuilder();
        // register DbContext
        _builder.RegisterType<AppDbContext>()
            .WithParameter("options", dbContextOptionsBuilder.Options)
            .InstancePerDependency();
    }
}

public class DatabaseFactory<T> : Disposable, IDatabaseFactory<T>
        where T : DbContext //, new()
{
    private T _dbContext;
    private AppDbContextOptionsBuilderHelper _appDbContextOptionsBuilderHelper;
    private DefaultDbContextOptionsBuilderHelper _defaultDbContextOptionsBuilderHelper;

    public DatabaseFactory()
    {
        this._appDbContextOptionsBuilderHelper = new AppDbContextOptionsBuilderHelper();  // TODO: refactor to ctor injection
        this._defaultDbContextOptionsBuilderHelper = new DefaultDbContextOptionsBuilderHelper();  // TODO: refactor to ctor injection
    }

    public T Get()
    {
        if (_dbContext == null)
            Create();
         return _dbContext;
    }

    private void Create()
    {
        switch (typeof(T).Name)
        {
            case "AppDbContext":
            {
                CreateAppDbContext();
                break;
            }
            case "DefaultDbContext":
            {
                CreateDefaultDbContext();
                break;
            }
        }
    }
    private void CreateAppDbContext()
    {
        var dbContextOptionsBuilder = _appDbContextOptionsBuilderHelper.GetDbContextOptionsBuilder();
        this._dbContext = new AppDbContext(dbContextOptionsBuilder.Options) as T;
    }
    //protected override void DisposeCore()
    //{
    //
        // cref: Autofac.Util.Disposable
        //
        //    //TODO: should I override Autofac.Util.Disposable here?
        //    var msg = "DatabaseFactory.DisposeCore() executing";
        //    if (_dbContext != null)
        //        _dbContext.Dispose();
    //}
}

public partial class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    { }
    public AppDbContext()
    {}
}

public class SystemSettingRepository : RepositoryBase<SystemSetting, AppDbContext>, ISystemSettingRepository
{
    public SystemSettingRepository(DatabaseFactory<AppDbContext> databaseFactory)
            : base(databaseFactory)
    { }
}

public interface ISystemSettingRepository : IRepository<SystemSetting>
{}

public partial interface IRepository<T> where T : class
{}

public abstract class RepositoryBase<T, U> : IRepositoryBase<T, U>
        where T : class
        where U : DbContext //, new()
{
    private U _dbContext;
    private readonly DbSet<T> _dbset;
    protected RepositoryBase(DatabaseFactory<U> databaseFactory)
    {
        DatabaseFactory = databaseFactory;
        _dbset = DataContext.Set<T>();
    }
    protected virtual DatabaseFactory<U> DatabaseFactory
    {
        get;
        private set;
    }

    protected virtual U DataContext
    {
        get { return _dbContext = DatabaseFactory.Get(); }
    }

    public virtual async Task<T> AddAsync(T dao)
    {
        EntityEntry<T> entityEntry = _dbset.Add(dao);
        var result = await SaveChangesAsync();
        if (result > 0 && entityEntry != null && entityEntry.Entity != null)
            return entityEntry.Entity;
        else
            return null;
    }
}

public interface IRepositoryBase<T, U> 
        where T : class
        where U : DbContext //, new()
{ }

1 Ответ

0 голосов
/ 19 сентября 2018

Проблема вызвана способом регистрации DatabaseFactory<>.Этот тип зарегистрирован как интерфейс IDatabaseFactory<>.Но это разрешается как само по себе в лямбда-аргументе метода WithParameter() при регистрации репозиториев:

 _builder.RegisterAssemblyTypes(_assembly)
        .AsClosedTypesOf(typeof(IRepository<>))
        .WithParameter(new ResolvedParameter((p, i) => p.Name == "databaseFactory",
                                             // resolving type it self
                                             // while it was registered as interface
                                             (p, i) => i.Resolve<DatabaseFactory<AppDbContext>>()))

Autofac не знает, как его разрешить, потому что у него нет соответствующей регистрации.Чтобы заставить ваш код работать, вы можете преобразовать DatabaseFactory как интерфейс:

.WithParameter(new ResolvedParameter((p, i) => p.Name == "databaseFactory",
                                     (p, i) => i.Resolve<IDatabaseFactory<AppDbContext>>()))

Или добавить AsSelf() вызов для регистрации:

_builder.RegisterGeneric(typeof(DatabaseFactory<>))
        .As(typeof(IDatabaseFactory<>))
        // Register also as DatabaseFactory<>
        .AsSelf()
        .InstancePerDependency();
...