Autofac - DataContext 未在生命周期结束时处理
Autofac - DataContext not being disposed at end of lifetime scope
我有一个命令行程序正在将数据导入我的系统。因为它将数据插入到许多表中,所以我需要更改跟踪。为了尝试防止作业随着时间的推移变慢,我使用 Autofac(我的依赖注入框架)创建了一个内部生命周期范围,我从中解析依赖关系。在每批结束时,我重新创建生命周期范围并获取我的依赖项的新实例。问题是,当我这样做时,我的 UnitOfWork 所依赖的 DataContext 不会每次都被刷新,从而导致作业变慢并最终在完成之前终止的情况。
我可以在调试时通过在我的 DbContext 上设置 'Make Object ID' 来看到这一点,例如
在每批之后,对象 ID 仍然是 $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);
}
像下面这样注册程序集接口
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 更改为始终 return Initialise 方法中的新上下文,而不是 return 如果它已经实例化,则使用相同的内容。
我有一个命令行程序正在将数据导入我的系统。因为它将数据插入到许多表中,所以我需要更改跟踪。为了尝试防止作业随着时间的推移变慢,我使用 Autofac(我的依赖注入框架)创建了一个内部生命周期范围,我从中解析依赖关系。在每批结束时,我重新创建生命周期范围并获取我的依赖项的新实例。问题是,当我这样做时,我的 UnitOfWork 所依赖的 DataContext 不会每次都被刷新,从而导致作业变慢并最终在完成之前终止的情况。
我可以在调试时通过在我的 DbContext 上设置 'Make Object ID' 来看到这一点,例如
在每批之后,对象 ID 仍然是 $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);
}
像下面这样注册程序集接口
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 更改为始终 return Initialise 方法中的新上下文,而不是 return 如果它已经实例化,则使用相同的内容。