1

J'ai récemment créé une solution et j'ai pensé que j'essaierais le conteneur DryIoC pour gérer l'injection de dépendances. Maintenant, comme avec beaucoup d'autres solutions DI que j'ai utilisées, la portée par défaut pour la réutilisation d'objet est transitoire. Cela semble toutefois poser un problème pour l'implémentation du modèle de référentiel que j'utilise depuis que DryIoC (et beaucoup d'autres solutions) ne peuvent pas enregistrer une liaison en tant que transitoire si la classe référencée implémente IDisposable. Par conséquent, j'ai temporairement recouru à l'enregistrement de mes dépôts avec Reuse.Singleton. Ceci est certainement une odeur de code pour moi, alors j'espérais que quelqu'un pourrait avoir des conseils sur la façon d'éviter cette situation - il se peut que je fasse un piètre travail de création d'un dépôt par exemple.Évitez le dépôt singleton (DryIoc) lorsque vous utilisez l'injection de dépendance

Voici le code que j'utilise pour créer le conteneur 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; 
} 

... et une mise en œuvre du référentiel exemple:

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 
} 

Répondre

1

Selon the documentation, vous avez 3 options:

N'autorise pas l'enregistrement du service transitoire à usage unique.
  1. Le comportement DryIoc par défaut.

    container.Register<X>(); // will throw exception 
    
  2. permettent d'enregistrer transitoire à usage unique, mais déléguer la responsabilité de disposer du service de conteneur utilisateur.

    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. Pour suivre (magasin) à usage unique dépendance transitoire dans son champ d'application de la réutilisation des propriétaire (le cas échéant), ou à la piste résolu à usage unique transitoire Portée ouverte courant (le cas échéant).

    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 
    

Comme vous pouvez le voir ci-dessus, le comportement par défaut vous attend de disposer explicitement lors de l'utilisation transitoire mode de vie.

Mais ils ont omis la 4ème option, qui est de trouver un autre conteneur DI. Je n'ai jamais utilisé DryIoC, mais cela me semble trop inquiétant pour que vous n'ayez pas à le faire avec d'autres conteneurs. Normalement, choisir la durée de vie correcte est ce qui détermine quand disposer d'une instance.

+0

Merci beaucoup pour l'information! Pourriez-vous fournir quelques exemples de contenants d'ID qui peuvent répondre à ce besoin? La raison pour laquelle j'ai utilisé DryIoC est parce qu'il a une grande performance et répond à mes exigences fonctionnelles. – spuriousGeek

+0

Il existe une liste de conteneurs .NET [ici] (https://github.com/danielpalme/IocPerformance), mais notez que les performances sont rarement le meilleur indicateur du conteneur à utiliser. La plupart ont des caractéristiques similaires, il s'agit simplement d'en trouver un qui est toujours activement pris en charge et qui répond à vos besoins. – NightOwl888

0

La documentation here explique pourquoi jetable transitoire est le problème et pourquoi le comportement par défaut de DryIoc a été sélectionné cette façon. Fondamentalement, le comportement est vous informer sur le problème et pas seulement en silence.

En ce qui concerne les autres récipients, il n'y a pas de préférence marquée pour la manipulation de transitoires particuliers. Voici la discussion liée à Microsoft.Extensions.DependencyInjection avec la participation de Autofac, StructureMap et d'autres développeurs de conteneurs.

BTW, DryIoc message d'erreur contient la pointe comment opter dans le problème.