Question

Maybe abstract typed factories are not an easy point to start with Windsor (2.5.3 if it matters) but I've got to do it anyway. I'm trying to build a factory giving back processors depending on message type. So far i've scavenged from different places following code:

public class Complicato
{
    public static void Do(string[] args)
    {
        IKernel kernel = new DefaultKernel();
        IWindsorContainer container = new WindsorContainer();

        kernel.AddFacility<TypedFactoryFacility>();

        container.Install();
        container.Register(

            Component.For<HandlerSelector, ITypedFactoryComponentSelector>(),

            AllTypes.FromThisAssembly().BasedOn(typeof(ITrier<>))
                .WithService.Base().Configure(conf => conf.LifeStyle.Is(LifestyleType.Transient)),
            Component.For<Factor>(),
            Component.For<ITryFactory>().AsFactory(c => c.SelectedWith<HandlerSelector>()).LifeStyle.Singleton);

        var factor = container.Resolve<Factor>();
        var factory = container.Resolve<ITryFactory>();
    }
}

public class HandlerSelector : DefaultTypedFactoryComponentSelector
{
    protected override Type GetComponentType(MethodInfo method, object[] arguments)
    {
        return typeof(ITrier<>).MakeGenericType(arguments[0].GetType());
    }
}

public class Factor
{
    private ITryFactory factory;

    public void Try(IWhat onto)
    {
        factory.GetTrier(onto).Try(onto);
    }
}


public interface ITryFactory
{
    ITrier<IWhat> GetTrier(IWhat onto);
    void Release(object elem);
}


public interface IWhat { }


public interface ITrier<in TWhat> where TWhat : IWhat
{
    void Try(TWhat input);
}


public class TrierYes : ITrier<WhatYes>
{
    public void Try(WhatYes input) { Console.WriteLine("Yes? " + input.Aye()); }
}

public class TrierNo : ITrier<WhatNot>
{
    public void Try(WhatNot input) { Console.WriteLine("No? " + input.Naa()); }
}

public class WhatYes : IWhat
{
    public bool Aye() { return true; }
}

public class WhatNot : IWhat
{
    public bool Naa() { return false; }
}

Main problem here is that id doesn't work. First I get Factor with factory of null and then as a consequence trying to resolve factory explicitely gives me ComponentActivator: could not proxy Factories.Complex.ITryFactory with inner message of The interceptor Castle.TypedFactory.Interceptor could not be resolved and "Keys (components with specific keys) - Castle.TypedFactory.Interceptor which was not registered" in container. I don't even know if the Handler selector works, it's not in question so far.

If I make ITrier not generic - it suddenly starts working but it's definitely not what I'm trying to achieve.

So do I make some silly beginners mistake in Windsor configuration or misunderstand the idea of typed factory?

For completeness sake, here's the exception message:

Castle.MicroKernel.ComponentActivator.ComponentActivatorException was unhandled
  Message=ComponentActivator: could not proxy Factories.Complex.ITryFactory
  Source=Castle.Windsor
  StackTrace:
       at Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateInstance(CreationContext context, Object[] arguments, Type[] signature) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\MicroKernel\ComponentActivator\DefaultComponentActivator.cs:line 166
  InnerException: Castle.MicroKernel.Resolvers.DependencyResolverException
       Message=The interceptor Castle.TypedFactory.Interceptor could not be resolved
       Source=Castle.Windsor
       StackTrace:
            at Castle.Core.InterceptorReference.Castle.MicroKernel.IReference<Castle.DynamicProxy.IInterceptor>.Resolve(IKernel kernel, CreationContext context) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\Core\InterceptorReference.cs:line 142
Was it helpful?

Solution

And the winner is

container.AddFacility<TypedFactoryFacility>(); // good code

instead of

kernel.AddFacility<TypedFactoryFacility>(); // bad code

Now I only have the issues of not injected factory and improper HandlerSelector.

NullReference was solved by introducing explicit initializing constructor to the Factor. I don't know why I thought it works without.

Final version of the handler interface is following:

public interface ITrier<out TWhat> where TWhat: IWhat
{
    void Try(IWhat input);
}

To permit covariance. Not über-elegant as requires unnecessary cast and handlers loosen their typedness. But this is cruel reality. You're either co or contra-variant.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top