使用依赖注入时避免使用单例存储库(DryIoc)

问题描述:

我最近创建了一个解决方案,并认为我会尝试使用DryIoC容器来处理依赖注入。现在,与我已经使用的许多其他DI解决方案一样,对象重用的默认范围是瞬态。然而,这似乎是我执行我使用的存储库模式的一个问题,因为如果被引用的类实现了IDisposable,DryIoC(以及许多其他解决方案)不能将绑定注册为临时模式。因此,我暂时使用Reuse.Singleton注册我的存储库。这对我来说绝对是一种代码味道,所以我希望有人可能会就如何避免这种情况提出一些建议 - 例如,我可能在创建存储库方面做得不好。使用依赖注入时避免使用单例存储库(DryIoc)

这里是我用来创建IoC容器代码:

private static Container ConstructNewContainer() 
{ 
    var container = new Container(Rules.Default); 
    container.Register(Made.Of(() => SettingsFactory.CreateSettings()));  
    container.Register<IRepository<tblMailMessage>, MailMessageRepository>(Reuse.Singleton); 
    container.Register<IRepository<ProcessedMailMessages>, ProcessedMailMessageRepository>(Reuse.Singleton); 
    container.Register<IParser, EmailParser>(); 
    container.Register<IMonitor, DatabaseMonitor>(); 
    return container; 
} 

...和实例库的实现:

public interface IRepository<T> 
{ 
    void Insert(T objectToInsert); 

    void Delete(int id); 

    void Update(T objectToUpdate); 

    void Save(); 

    T GetById(long id); 

    IEnumerable<T> Get(); 

    T Last(); 

    bool Exists(int id); 
} 

public class MailMessageRepository : IRepository<tblMailMessage>, IDisposable 
{ 
    private bool _disposed; 
    private readonly CoreDataModel _model; 

    public MailMessageRepository() 
    { 
     _model = new CoreDataModel(); 
    } 

    public void Delete(int id) 
    { 
     var objectToDelete = _model.tblMailMessages.Find(id); 
     if (objectToDelete != null) _model.tblMailMessages.Remove(objectToDelete); 
    } 

    public void Update(tblMailMessage objectToUpdate) => _model.Entry(objectToUpdate).State = EntityState.Modified; 

    public void Save() => _model.SaveChanges(); 

    public IEnumerable<tblMailMessage> Get() => _model.tblMailMessages.ToList(); 

    public tblMailMessage Last() => _model.tblMailMessages.OrderByDescending(x => x.DateSubmitted).FirstOrDefault(); 

    public bool Exists(int id) => _model.tblMailMessages.SingleOrDefault(x => x.MailMessageID == id) != null; 

    public void Insert(tblMailMessage objectToInsert) => _model.tblMailMessages.Add(objectToInsert); 

    public tblMailMessage GetById(long id) => _model.tblMailMessages.SingleOrDefault(x => x.MailMessageID == id); 

    #region Dispose 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!_disposed) 
     { 
      if (!disposing) 
      { 
       _model.Dispose(); 
      } 
     } 

     _disposed = true; 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 
    #endregion 
} 

the documentation,你有3种选择:

  1. 不允许注册一次性短暂服务。 默认的DryIoc行为。

    container.Register<X>(); // will throw exception 
    
  2. 允许注册一次性短暂的,但委托服务配置到集装箱用户的责任。

    container.Register<X>(setup: Setup.With(allowDisposableTransient: true)); 
    
    // or allow globally for all container registrations: 
    var container = new Container(rules => rules.WithoutThrowOnRegisteringDisposableTransient()); 
    
    container.Register<X>(); // works, but dispose is up to User 
    
  3. 要跟踪在其所有者重用范围(存储)一次性瞬态依赖性(如果有的话),或者跟踪解决了当前打开范围一次性瞬态(如果有的话)。

    container.Register<X>(setup: Setup.With(trackDisposableTransient: true)); 
    
    // or track globally for all container registrations: 
    var container = new Container(rules => rules.WithTrackingDisposableTransients()); 
    
    // will be tracked in XUser parent in singleton scope and disposed with container as all singletons 
    container.Register<XUser>(Reuse.Singleton); 
    container.Register<X>(); 
    
    // or tracking in open scope 
    using (var scope = container.OpenScope()) 
        scope.Resolve<X>; // will be disposed on exiting of using block 
    

正如你可以在上面看到,默认的行为,希望你用短暂的生活方式时,明确处置。

但他们没有找到第四个选项,即找到另一个DI容器。我从来没有使用过DryIoC,但是这似乎太多了,不必担心你不需要使用其他容器。通常,选择正确的生命周期是决定何时处置实例的原因。

+0

非常感谢您的信息!你能否提供几个DI容器的例子,可以处理这个开箱即用的问题? 我使用DryIoC的原因是因为它具有卓越的性能并满足我的功能要求。 – spuriousGeek

+0

有一个.NET容器的列表[在这里](https://github.com/danielpalme/IocPerformance),但请注意,性能很少是容器使用的最佳尺度。大多数都有类似的功能,只是找到一个仍然得到积极支持,适合您的需求的问题。 – NightOwl888

文档here解释了为什么一次性瞬变是问题,并解释了为什么选择DryIoc默认行为。基本上,行为是通知您有关问题而不只是默默无闻地去与它。

关于其他容器,对于特定的一次性瞬变处理没有强烈的偏好。这里是关于Microsoft.Extensions.DependencyInjection的讨论,由Autofac,StructureMap和其他容器开发人员参与。

Btw,DryIoc错误消息包含提示如何选择在问题。