バックエンドサービスでは、作業単位パターンを使用します。オブジェクトの廃棄に関連する何かが欠けているのではないかと思っていました。
まず、これは私がこれまでに持っているコードであり、機能します。このサービスは、リクエストハンドラを呼び出すだけです。
[GlobalExceptionHandlerBehaviour(typeof(GlobalExceptionHandler))]
public class CustomerService : ICustomerService
{
public void AddCustomer(AddCustomerRequest request)
{
ObjectFactory.GetInstance<AddCustomerRequestHandler>().Execute(request);
}
}
リクエストハンドラは次のようになります。
public class AddCustomerRequestHandler
{
private readonly IUnitOfWork _unitOfWork;
private readonly ICustomerRepository _customerRepository;
public AddCustomerRequestHandler(IUnitOfWork unitOfWork, ICustomerRepository customerRepository)
{
_unitOfWork = unitOfWork;
_customerRepository = customerRepository;
}
public void Execute(AddCustomerRequest request)
{
var customer = new Customer(request.Id, request.CompanyName);
_customerRepository.Add(customer);
_unitOfWork.Commit();
}
}
作業単位は次のように定義されます。
public interface IUnitOfWork
{
void Commit();
}
public class UnitOfWork : IUnitOfWork
{
private readonly IDatabaseFactory<EfTrackerDbContext> _databaseFactory;
private EfTrackerDbContext _dataContext;
public UnitOfWork(IDatabaseFactory<EfTrackerDbContext> databaseFactory)
{
_databaseFactory = databaseFactory;
}
public EfTrackerDbContext DataContext
{
get { return _dataContext ?? (_dataContext = _databaseFactory.Get()); }
}
public void Commit()
{
DataContext.Commit();
}
}
EfTrackerDbContextは、実際のEFコンテキストです。
public class EfTrackerDbContext : DbContext, IUnitOfWork
{
public DbSet<Customer> Customers { get; set; }
public virtual void Commit()
{
base.SaveChanges();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Customer>().ToTable("Customer");
}
}
そして、DatabaseFactoryは次のようなものです。
public class DatabaseFactory<TContext> : DisposableObject, IDatabaseFactory<TContext> where TContext : DbContext, new()
{
private TContext _dataContext;
public TContext Get()
{
return _dataContext ?? (_dataContext = new TContext());
}
protected override void DisposeManagedResources()
{
if (_dataContext != null)
{
_dataContext.Dispose();
_dataContext = null;
}
}
}
CustomerRepository:
public interface ICustomerRepository : IRepository<Customer>
{
IQueryable<Customer> Customers { get; }
}
public class CustomerRepository : RepositoryBase<EfTrackerDbContext, Customer>, ICustomerRepository
{
public CustomerRepository(IDatabaseFactory<EfTrackerDbContext> databaseFactory)
: base(databaseFactory)
{
}
public IQueryable<Customer> Customers
{
get { return DataContext.Customers; }
}
}
ご覧のとおり、すべてが注入されています。登録は次のようになります。
For<IDatabaseFactory<EfTrackerDbContext>>().HybridHttpOrThreadLocalScoped().Use<DatabaseFactory<EfTrackerDbContext>>();
For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<UnitOfWork>();
For<ICustomerRepository>().HybridHttpOrThreadLocalScoped().Use<CustomerRepository>();
さて、問題はオブジェクトの処分についてです。IDisposableが実装される唯一の場所は、_datacontextが破棄されるDatabaseFactoryです。それだけでは不十分だと思うので、次の質問があります。
- AddCustomerRequestHandlerが注入されるため、AddCustomer()サービス操作が終了し、ガベージコレクションが開始されると破棄されます。これは問題ありませんか、それともAddCustomer()操作の最後にAddCustomerRequestHandlerでDisposeを明示的に呼び出して、IDisposableを実装する必要がありますか?
- UnitOfWorkもIDisposableを実装する必要があり、明示的に呼び出す必要がありますか?
- EfTrackerDbContextを破棄する方法は?
- その他の発言?
要するに、私はサービス運用が終了したらすぐにすべてを処分する正しい方法を探しています。
アドバイスありがとう、L