IDisposable on an injected repository

后端 未结 2 700
执笔经年
执笔经年 2021-02-04 16:33

I have the following ADO .Net Repository

public class Repository : IRepository, IDisposable
{
   private readonly IUnitOfWork UnitOfWork;
   private SqlConnectio         


        
相关标签:
2条回答
  • 2021-02-04 17:12

    The problem you have is one of ownership. The UserDomainService class does not create the IRepository, yet it still takes the ownership of that instance, since it disposes it.

    The general rule is that the one who creates an object should distroy it. In other words, he who creates the object is the owner, and the owner shall destroy that object.

    There are two solutions to your problem.

    1. Create a IRepositoryFactory, as Adam clearly explains. A CreateNewRepository() method on such a factory will clearly communicate that the caller gets the ownership and should dispose that created repository.

    2. Let the one who creates (and injects) that repository deal with the disposal of that repository. Either you do this manually in your WCF service, or you use an IoC/DI framework. In case you use a DI framework, you should probably look at a Per Web Request lifetime, or something similar.

    Last note, your IRepository implements IDisposable. When choosing solution 2, you can remove the IDisposable interface from IRepository, which hides the fact that resources are involved from the application. Hiding IDisposable from the application is a good thing, since that interface is a leaky abstraction. You already encountered this, since calling Dispose from within the application, breaks the entire application.

    0 讨论(0)
  • 2021-02-04 17:15

    Inject a factory that creates the instances you need, not an instance itself.

    Take an IRepositoryFactory so that you can create an IRepository and dispose of it each time you use it. This way, neither the domain service or the factory would need to be disposable. Also, and importantly, you keep the code abstract by still injecting the implementation as opposed to hard-coding it.

    public class UserDomainService : IUserDomainService
    {
       private readonly IRepositoryFactory RepositoryFactory;
    
       public UserDomainService(IRepositoryFactory factory)
       {
          RepositoryFactory = factory;
       }
    
       public User CreateNewUser(User user)
       {
          using (IRepository repository = RepositoryFactory.Create())
          {
             var user = repository.FindBy(user.UserName);
             if(user != null)
                throw new Exception("User name already exists!");
    
             repository.Add(user);
             repository.Commit();
          }
       }
    }
    

    You don't always have to inject the type you need. On reading up on Castle Windsor (whose mindset is register-resolve-release), you find that if you want to Resolve stuff at an indeterminate time in the app's life, it is suggested to use Type Factories.

    You know you will need a Repository, but don't know when. Instead of asking for a repository, ask for something that creates them. The level of abstraction is thus maintained and you have not leaked any implementation.

    0 讨论(0)
提交回复
热议问题