2016-12-21 5 views
2

J'essaie d'obtenir la construction de l'objet comme indiqué ci-dessous, ce qui crée un nouveau DbContext dans l'utilisation et est donc éliminé en quittant la portée d'utilisation. Donc, comme indiqué ci-dessous, j'ai créé deux objets de processeur dans deux portées distinctes. Je veux y parvenir en utilisant Castle Windsor.Utilisation de Castle Windsor J'ai besoin d'une nouvelle instance d'un objet lors du démarrage d'une nouvelle portée

 using (var context = new DbContext()) 
     { 
      var processor = new Processor(context, new Parser(context, new Logger(context)), new Logger(context)); 
     } 

     using (var context = new DbContext()) 
     { 
      var processor = new Processor(context, new Parser(context, new Logger(context)), new Logger(context)); 
     } 

J'ai posé une question similaire avant Castle Windsor propogating inline dependencies qui a suggéré d'utiliser les étendues, mais je ne peux pas le faire fonctionner comme je le veux. Voir le programme entier ci-dessous.

using Castle.MicroKernel.Lifestyle; 
using Castle.MicroKernel.Registration; 
using Castle.Windsor; 
using System; 

namespace IOCTesting 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var container = new WindsorContainer(); 

      container 
       .Register(Component.For<IProcessor>() 
       .ImplementedBy<Processor>()); 

      container 
       .Register(Component.For<IParser>() 
       .ImplementedBy<Parser>()); 

      container 
       .Register(Component.For<ILogger>() 
       .ImplementedBy<Logger>()); 

      container.Register(Component.For<DbContext>() 
       .ImplementedBy<DbContext>() 
       .LifeStyle 
       .Scoped()); 

      using (container.BeginScope()) 
      { 
       var processor = container.Resolve<IProcessor>(); 
      } 

      using (container.BeginScope()) 
      { 
       var processor = container.Resolve<IProcessor>(); 
      } 
     } 
    } 

    public class DbContext : IDisposable 
    { 
     public void Dispose() 
     { 
      Console.WriteLine("DbContext disposed."); 
     } 
    } 

    public class Processor : IProcessor 
    { 
     private readonly DbContext _context; 
     private readonly ILogger _logger; 
     private readonly IParser _parser; 

     public Processor(DbContext context, IParser parser, ILogger logger) 
     { 
      _context = context; 
      _parser = parser; 
      _logger = logger; 
     } 
    } 

    public class Parser : IParser 
    { 
     private readonly DbContext _context; 
     private readonly ILogger _logger; 

     public Parser(DbContext context, ILogger logger) 
     { 
      _context = context; 
      _logger = logger; 
     } 
    } 

    public class Logger : ILogger 
    { 
     private readonly DbContext _context; 

     public Logger(DbContext context) 
     { 
      _context = context; 
     } 
    } 

    public interface IProcessor 
    { 
    } 

    public interface IParser 
    { 
    } 

    public interface ILogger 
    { 
    } 
} 

En sortant de la première container.BeginScope() la méthode Dispose sur DbContext est appelée, mais sur le deuxième appel à conteneur. BeginScope() La méthode Dispose n'est pas appelée lors de la sortie de la deuxième étendue.

Cela implique que le conteneur me soit donné la même instance DbContext disposée lorsque le second conteneur. BeginScope() est appelée. En substance, j'ai besoin que le DbContent soit transitoire au sein du container.BeginScope() et le conteneur me donne une nouvelle instance DbContext sur chaque portée nouvellement créée afin qu'elle soit toujours éliminée lorsque la portée est quittée.

J'espère que cela a du sens.

Répondre

2

Les codes IProcessor, IParser et ILogger doivent également être enregistrés en tant que Scoped.

container.Register(Component.For<IProcessor>() 
    .ImplementedBy<Processor>() 
    .LifeStyle.Scoped()); 

Faites ceci pour tous les composants qui dépendent de DBContext.

Si aucun mode de vie n'est explicitement défini, la valeur par défaut est singleton. Ainsi, la première fois que vous résolvez un IProcessor le singleton est instancié, ses dépendances sont résolues, y compris le champ DBContext. À la fin de la première portée, le DBContext est libéré et éliminé, mais le singleton IProcessor a toujours un référencé à celui disposé DBContext. Lorsque vous résolvez un IProcessor dans la deuxième portée, le singleton déjà instancié est renvoyé, contenant le DBContext déjà disposé.

+0

Merci Andy pour votre explication et vous avez raison. Vous l'avez mentionné dans la réponse à l'autre question, mais dans ma hâte, je n'ai pas digéré complètement ce que vous disiez. L'exemple que j'ai donné est en fait un exemple d'un problème dans notre base de code existante. J'essaie de lire un message hors de la file d'attente et j'ai besoin que le dbcontext soit actif pendant le traitement du message. Certains des objets qui sont utilisés pour traiter le message sont des Singletons et, comme vous le dites correctement, ce sont ces objets qui font référence au dbcontext. Je devrai refactoriser le code pour supporter ce scénario. – dezzy