使用依赖注射时,请避免单例存储库(Dryioc)



我最近创建了一个解决方案,并认为我会尝试使用Dryioc容器来处理依赖性注入。现在,与我使用过的许多其他DI解决方案一样,对象重用的默认范围是 transient 。然而,这似乎是我使用的存储库模式的问题,因为Dryioc(以及许多其他解决方案)如果引用的类实现可识别的,则无法注册绑定为瞬态。结果,我暂时诉诸于 reuse.singleton 向我的存储库注册。这绝对是我的代码气味,所以我希望有人可能会对如何避免这种情况有一些建议 - 例如,我在创建存储库方面做得很差。

这是我用来创建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
}

此处的文档解释了为什么可操作的瞬态是问题,以及为什么以这种方式选择了dryioc默认行为。基本上,行为是通知您问题,而不仅仅是与之相关。

关于其他容器,对特定的一次性瞬态处理没有强烈的偏爱。以下是与Microsoft.extensions.epententions的讨论。

btw,dryioc错误消息包含技巧如何选择加入问题。

根据文档,您有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,但这似乎太担心了,您不必与其他容器一起使用。通常,选择正确的寿命是决定何时处置实例的方法。

最新更新