带有DI的Windows服务 - 存储库注入

时间:2016-04-06 13:16:20

标签: entity-framework dependency-injection windows-services

我有一个专为依赖注入设计的Windows服务。该服务运行多个线程计时器,每个计时器轮询一个数据库,有时会处理其中的记录。

注入服务的一个依赖项是Repository对象,它提供对数据库的必需访问。存储库依次封装实体框架DbContext。

目前,在服务启动时会注入存储库的一个实例,并在服务器停止之前一直保持可用状态。我不喜欢这个有两个原因:

  • DbContext大部分时间处于空闲状态,但保持数据库连接打开
  • DbContext变得陈旧;已读入数据的外部更改未反映

我想更改存储库的管理方式,以便每次调用计时器的execute方法都会获得一个新的存储库实例,同时将存储库保持为可注入服务。

我首选的方法是注入一个RepositoryFactory对象而不是存储库,以便定时器执行方法可以创建自己的存储库。但是,尽管存储库实例已成功创建,并且通过它(GET)对数据库的第一次访问成功,但下一次数据库访问(UPDATE方法中包含的另一个GET)将失败,因为DbContext似乎已被释放。

任何人都可以了解为何会发生这种情况,并提出解决方案吗?如果符合实例化要求,我可以使用除工厂以外的模式。

//DI configuration
public static void AddRepository(this IServiceCollection services, string connectionString)
{
    services.AddEntityFramework()
        .AddSqlServer()
        .AddDbContext<MyDbContext>(options =>
            options.UseSqlServer(connectionString));

    services.AddScoped<IRepository, Repository>();
    services.AddScoped<IRepositoryFactory, RepositoryFactory>(Factory);
}

private static readonly Func<IServiceProvider, RepositoryFactory> Factory = (_serviceProvider) =>
{
    Console.WriteLine("ServiceProvider instantiated: {0}", _serviceProvider != null);
    return new RepositoryFactory(_serviceProvider);
};

//Windows service constructor
public AllocationService(IRepositoryFactory factory, IMapperConfiguration mapperConfig)
{
    _repositoryFactory = factory;
    _mapperConfig = mapperConfig as MapperConfiguration;
    InitializeComponent();
}

//Timer execution method
private void _registrationTimer_Elapsed(object stateObject)
{
    EventLog.WriteEntry(Constants.AllocationSourceName, string.Format("Registration Timer Elapsed on thread {0}", Thread.CurrentThread.ManagedThreadId), EventLogEntryType.Information, (int)UseCaseType.Register);

    try
    {
        using (var repository = _repositoryFactory.Create())
        {
            //query the database for Approved Assets, 
            var list = repository.GetRegistrations(Status.Approved);
            EventLog.WriteEntry(Constants.AllocationSourceName, string.Format("{0} registrations with status=Approved", list.Count()), EventLogEntryType.Information, (int)UseCaseType.Register);

            foreach (var registration in list)
            {
                try
                {
                    //some processing removed here for simplicity

                    //update database
                    registration.Status = Status.Allocated;
                    //exception thrown here (see below)
                    repository.UpdateRegistration(registration);
                }
                catch (Exception ex)
                {
                    //Log any problems and continue
                    EventLog.WriteEntry(Constants.AllocationSourceName, ex.ToString(), EventLogEntryType.Error, (int)UseCaseType.Register);
                }
            }
        }
    }
    catch (Exception ex)
    {
        //Log any problems on saving
        EventLog.WriteEntry(Constants.AllocationSourceName, ex.ToString(), EventLogEntryType.Error, (int)UseCaseType.Register);
    }
}

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'MyDbContext'.
   at Microsoft.Data.Entity.DbContext.get_ServiceProvider()
   at Microsoft.Data.Entity.DbContext.Microsoft.Data.Entity.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.Data.Entity.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.Data.Entity.Internal.InternalDbSet`1.<.ctor>b__2_0()
   at Microsoft.Data.Entity.Internal.LazyRef`1.get_Value()
   at Microsoft.Data.Entity.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()
   at System.Linq.Queryable.Any[TSource](IQueryable`1 source, Expression`1 predicate)
   at RegistryApp.Repository.Repository.ProcessAsset(Asset asset) in C:\svn\Client Applications\ITC\RegistryApp\RegistryApp.Repository\Repository.cs:line 364
   at RegistryApp.Repository.Repository.UpdateAsset(Asset asset) in C:\svn\Client Applications\ITC\RegistryApp\RegistryApp.Repository\Repository.cs:line 270

0 个答案:

没有答案