Search code examples
dependency-injectioncastle-windsor

Castle Windsor propagating inline dependencies


I am trying to achieve object construction as shown below,

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

but using Castle Windsor. I am using inline dependencies as the code shows below, but as the Castle Windsor documentation states "Inline dependencies don't get propagated" Castle Windsor passing arguments. How can I achieve this another way?

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

namespace IOCTesting
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new DbContext())
            {
                var processor = new Processor(context, new Parser(context, new Logger(context)), new Logger(context));
            }

            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>());


            //[1] Creating my scope object here. (context)
            using (var context = new DbContext())
            {
                var processor = container.Resolve<IProcessor>(new { context = context });
            }
        }
    }

    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;

        //Dependency context passed in is the same object within the scope. See [1]
        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;

        //Dependency context passed in is the same object within the scope. See [1]
        public Parser(DbContext context, ILogger logger)
        {
            _context = context;
            _logger = logger;
        }
    }

    public class Logger : ILogger
    {
        private readonly DbContext _context;

        //Dependency context passed in is the same object within the scope. See [1]
        public Logger(DbContext context)
        {
            _context = context;
        }
    }

    public interface IProcessor
    {
    }

    public interface IParser
    {
    }

    public interface ILogger
    {
    }
}

Solution

  • You need to look at scoping; at the moment you're not specifying a scope so all dependencies will be singletons. Register DBContext along with ILogger, IParser, and IProcessor all with the Scoped lifestlye. E.G.

    container.Register(Component.For<DBContext>()
        .ImplementedBy<DBContext>()
        .Lifestyle.Scoped);
    

    Then you need to resolve your dependencies and use them within a scope. This would normally be managed in infrastructure, but at its simplest would look like this:

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

    Now a new DBContext will be created per scope and disposed when the container scope ends. You don't have to worry about initialising the DBContext or passing it to the Resolve method.