I'm using Castle Windsor and I'm trying to set up a cache on a TypedFactory using the decorator pattern. It works fine until I'm trying to dispose of the Windsor container (when shutting down the application). Basically, my problem is that the TypedFactory is already disposed when I'm trying to dispose of the CachedFactory.
Here is a simplified example of my problem:
using System;
using System.Collections.Generic;
using System.Threading;
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
// Setting up the container
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component.For<IItemFactory>().ImplementedBy<CachedItemFactory>(), //decorator pattern
Component.For<IItemFactory>().AsFactory(),
Component.For<IItem>().ImplementedBy<Item>().LifestyleTransient()
);
// Resolving
var itemFactory = container.Resolve<IItemFactory>();
// Desired behavior. Works as expected.
IItem item1 = itemFactory.Create("Item1");
IItem item2 = itemFactory.Create("Item2");
IItem anotherItem1 = itemFactory.Create("Item1");
Console.WriteLine("Item1 == Item2: {0}", item1 == item2); //false
Console.WriteLine("Item1 == anotherItem1: {0}", item1 == anotherItem1); //true
// Here is my problem. It throws ObjectDisposedException from _itemFactory in the Dispose function of CachedItemFactory
container.Dispose();
Console.WriteLine("End of program");
Console.ReadKey();
}
}
public interface IItem
{
string Name { get; }
}
public class Item : IItem
{
public Item(string name)
{
Name = name;
Thread.Sleep(1000); //It takes time to create this object
}
public string Name { get; private set; }
}
public interface IItemFactory
{
IItem Create(string name);
void Release(IItem item);
}
public class CachedItemFactory : IItemFactory, IDisposable
{
private readonly Dictionary<string, IItem> _cache = new Dictionary<string, IItem>();
private readonly IItemFactory _itemFactory;
public CachedItemFactory(IItemFactory itemFactory)
{
_itemFactory = itemFactory;
}
public IItem Create(string name)
{
if (!_cache.ContainsKey(name))
_cache.Add(name, _itemFactory.Create(name));
return _cache[name];
}
public void Release(IItem item)
{
}
public void Dispose()
{
foreach (var item in _cache)
{
_itemFactory.Release(item.Value);
}
_cache.Clear();
}
}
}
Any ideas of what I'm doing wrong? Any conceptual (architectural) errors?
I tried the following with no success:
- Registering the TypedFactory before the CachedItemFactory (and marking the CachedItemFactory as IsDefault): not working, same error
- Implementing a basic factory by hand instead of using the TypedFactory: same problem
This worked:
- Implementing a basic factory by hand, registering it before the CachedItemFactory and marking the CachedItemFactory as IsDefault... but it feels wrong (fragile)...
Any comments?
Thanks a lot!