I am trying to achieve object construction as shown below which creates a new DbContext
within the using and hence gets disposed when leaving the using scope. So as shown below I have created two processor objects in two separate using scopes. I want to achieve this using Castle Windsor
.
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));
}
I have asked a similar question before Castle Windsor propogating inline dependencies which suggested using scopes but I can't get it to work the way I want. See the entire program below.
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
{
}
}
On exiting the first container.BeginScope()
the Dispose
method on DbContext
is called, but on the second call to container. BeginScope()
the Dispose
method is not called when exiting the second scope.
This implies the container is given me the same disposed DbContext instance when the second container. BeginScope()
is called. In essence, I need the DbContent
to be transient within the container.BeginScope()
and the container give me a new DbContext
instance on every newly created scope so it is always disposed when the scope is exited.
Hopefully that makes sense.
The
IProcessor
,IParser
, andILogger
also need to be registered asScoped
.Do this for all components that depend on
DBContext
.If no lifestyle is explicitly set the default is singleton. So the first time you resolve an
IProcessor
the singleton is instantiated, it's dependencies are resolved including the scopedDBContext
. At the end of the first scope theDBContext
is released and disposed, but the singletonIProcessor
still has a referenced to that disposedDBContext
. When you resolve anIProcessor
in the second scope the already instantiated singleton is returned, containing the already disposedDBContext
.