Autofac - DataContext не удаляется в конце срока действия - PullRequest
0 голосов
/ 30 января 2019

У меня есть программа командной строки, которая импортирует данные в мою систему.Поскольку он вставляет данные во многие таблицы, мне требуется отслеживание изменений.Чтобы попытаться предотвратить замедление работы с течением времени, я использовал Autofac (мою структуру внедрения зависимостей), чтобы создать внутреннюю область жизни, из которой я разрешаю зависимости.В конце каждого пакета я воссоздаю область действия на всю жизнь и получаю новые экземпляры моих зависимостей.Проблема в том, что когда я это делаю, мой DataContext, от которого зависит UnitOfWork, не обновляется каждый раз, что приводит к ситуации, когда задание замедляется и в конечном итоге завершает работу до завершения.

Я могу видеть это при отладке, установив 'Make Object ID' на моем DbContext, например,

enter image description here

После каждой партии,идентификатор объекта остается $ 2, демонстрируя, что экземпляр DataContext не получает новый экземпляр.Почему он не получает новый экземпляр?

Мой код выглядит примерно так:

foreach (var batch in data.Batch(10))
{
    using (var scope = LifetimeScope.BeginLifetimeScope(b =>
    {
        b.RegisterType<UnitOfWork>.AsImplementedInterfaces().PropertiesAutowired().InstancePerLifetimeScope();
        b.RegisterType<MyService1>.AsImplementedInterfaces().PropertiesAutowired().InstancePerLifetimeScope();
        b.RegisterType<MyService2>.AsImplementedInterfaces().PropertiesAutowired().InstancePerLifetimeScope();
        b.RegisterGeneric(typeof(EntityBaseRepository<>)).As(typeof(IEntityBaseRepository<>)).InstancePerLifetimeScope();
    }))
    {
        UnitOfWork = scope.Resolve<IUnitOfWork>();
        MyService1 = scope.Resolve<IMyService1>();
        MyService2 = scope.Resolve<IMyService2>();
        Thing1Repository = scope.Resolve<IEntityBaseRepository<Thing1Repository>>();
        Thing2Repository = scope.Resolve<IEntityBaseRepository<Thing2Repository>>();

        foreach (var row in batch)
        {
            try
            {
                ParseRow(row);
            }
            catch (Exception e)
            {
                JobLogger.Error(e, "Failed to parse row. Exception: " + e.Message);
                throw;
            }

        }
    }
}

Насколько я понимаю, когда я получаю новый экземпляр моих зависимостей, дочерние зависимости также получат новые экземпляры?Почему оригинальный DataContext все еще висит?

Мой UnitOfWork выглядит следующим образом:

public class UnitOfWork : Disposable, IUnitOfWork
{
    private readonly IDbFactory _dbFactory;
    private DataContext _dbContext;

    public UnitOfWork(IDbFactory dbFactory)
    {
        _dbFactory = dbFactory;
    }

    public DataContext DbContext => _dbContext ?? (_dbContext = _dbFactory.Initialise());

    public void Commit()
    {
        DbContext.Commit();
    }
}

Мой DbFactory отвечает за создание нового экземпляра моего DataContext:

public class DbFactory : Disposable, IDbFactory
{
    DataContext _dbContext;

    public DbFactory()
    {
        _dbContext = new DataContext();
    }

    public DataContext Initialise()
    {
        return _dbContext ?? (_dbContext = new DataContext());
    }

    protected override void DisposeCore()
    {
        _dbContext?.Dispose();
    }
}

Мои службы регистрируются путем сканированиясборка при первом запуске программы путем вызова этого метода:

AutofacConfig.InitialiseJobRunner();

Внутри этого метода я регистрирую свои типы следующим образом:

builder.RegisterType<DataContext>().AsSelf().InstancePerMatchingLifetimeScope(lifetimeScope);
builder.RegisterGenericInstance(typeof(EntityBaseRepository<>), typeof(IEntityBaseRepository<>), lifetimeScope);
builder.RegisterAssemblyInterfaces(Assembly.Load(Data), lifetimeScope);

RegisterAssemblyInterfaces реализован следующим образом:

public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle>
        RegisterAssemblyInterfaces(this ContainerBuilder builder, Assembly assembly, object lifetimeScope)
{
    return builder.RegisterAssemblyTypes(assembly)
        .AsImplementedInterfaces()
        .InstancePerMatchingLifetimeScope(lifetimeScope);
}

1 Ответ

0 голосов
/ 30 января 2019

Когда вы регистрируете интерфейсы сборки, как показано ниже

public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle>
    RegisterAssemblyInterfaces(this ContainerBuilder builder, Assembly assembly, object lifetimeScope)
{
    return builder.RegisterAssemblyTypes(assembly)
        .AsImplementedInterfaces()
        .InstancePerMatchingLifetimeScope(lifetimeScope);
}

, я предполагаю, что ваша DbFactory также зарегистрирована таким образом.В таком случае (в соответствии с: https://autofac.readthedocs.io/en/latest/lifetime/instance-scope.html#instance-per-matching-lifetime-scope) вы получите тот же экземпляр вашей фабрики, что и у вашей дочерней области без имени.Попробуйте добавить

b.RegisterType<DbFactory>.AsImplementedInterfaces().PropertiesAutowired().InstancePerLifetimeScope();

в ваш цикл или измените DbFactory так, чтобы он всегда возвращал новый контекст в методе Initialise, вместо этого возвращая тот же самый, если он уже создан.

...