user47589
user47589

Reputation:

Windsor TypedFactoryFacility broken?

I'm trying to create a typed factory as per Windsor's example. This is my factory interface:

public interface ICustomJsonResultFactory
{
    JsonResult Create();
}

In my global.asax, I'm setting up the Windsor container by first adding the following two facilities:

.AddFacility<FactorySupportFacility>()
.AddFacility<TypedFactoryFacility>();

After that's done, I register my components:

Component.For<JsonResult>()
    .ImplementedBy<CustomJsonResult>()
    .LifestyleTransient(),
Component.For<ICustomJsonResultFactory>()
    .AsFactory())

One of my controllers has a ICustomJsonResultFactory property. When I try resolving the controller, I get the following in my logs:

Castle.Core.DependencyResolution: DEBUG 8 - 
    Client:     DefaultTypedFactoryComponentSelector / ITypedFactoryComponentSelector
    Model:      Dependency 'getMethodsResolveByName' type 'System.Boolean'
    Dependency: True
Castle.Core.DependencyResolution: DEBUG 8 - 
    Client:     DefaultTypedFactoryComponentSelector / ITypedFactoryComponentSelector
    Model:      Dependency 'fallbackToResolveByTypeIfNameNotFound' type 'System.Boolean'
    Dependency: False
Castle.Core.DependencyResolution: DEBUG 8 - 
    Client:     TypedFactoryInterceptor
    Model:      Dependency 'kernel' type 'Castle.MicroKernel.IKernelInternal'
    Dependency: Castle.MicroKernel.DefaultKernel
Castle.Core.DependencyResolution: DEBUG 8 - 
    Client:     TypedFactoryInterceptor
    Model:      Dependency 'componentSelector' type 'Castle.Facilities.TypedFactory.ITypedFactoryComponentSelector'
    Dependency: Castle.Facilities.TypedFactory.DefaultTypedFactoryComponentSelector
A first chance exception of type 'System.ArgumentException' occurred in Castle.Windsor.dll
A first chance exception of type 'System.ArgumentException' occurred in Castle.Windsor.dll
A first chance exception of type 'Castle.MicroKernel.ComponentActivator.ComponentActivatorException' occurred in Castle.Windsor.dll

I think this part is important, so I'm pointing it out:

Castle.Windsor Warning: 0 : Exception when resolving optional dependency Dependency 'JsonResultFactory' type 'CompanyName.Web.Mvc.ICustomJsonResultFactory' on component CompanyName.Web.OrderProcessing.Controllers.PickTicketController., Castle.MicroKernel.ComponentActivator.ComponentActivatorException: ComponentActivator: could not proxy CompanyName.Web.Mvc.ICustomJsonResultFactory ---> System.ArgumentException: Component CompanyName.Web.Mvc.ICustomJsonResultFactory is not a typed factory. TypedFactoryInterceptor only works with typed factories.

   at Castle.Facilities.TypedFactory.Internal.TypedFactoryInterceptor.SetInterceptedComponentModel(ComponentModel target)
at Castle.Windsor.Proxy.AbstractProxyFactory.SetOnBehalfAware(IOnBehalfAware onBehalfAware, ComponentModel target)
at Castle.Windsor.Proxy.AbstractProxyFactory.ObtainInterceptors(IKernel kernel, ComponentModel model, CreationContext context)
at Castle.Windsor.Proxy.DefaultProxyFactory.Create(IKernel kernel, Object target, ComponentModel model, CreationContext context, Object[] constructorArguments)
at Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateInstance(CreationContext context, ConstructorCandidate constructor, Object[] arguments)
--- End of inner exception stack trace ---
at Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateInstance(CreationContext context, ConstructorCandidate constructor, Object[] arguments)
at Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.Instantiate(CreationContext context)
at Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.InternalCreate(CreationContext context)
at Castle.MicroKernel.ComponentActivator.AbstractComponentActivator.Create(CreationContext context, Burden burden)
at Castle.MicroKernel.Lifestyle.AbstractLifestyleManager.CreateInstance(CreationContext context, Boolean trackedExternally)
at Castle.MicroKernel.Lifestyle.SingletonLifestyleManager.Resolve(CreationContext context, IReleasePolicy releasePolicy)
at Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, Boolean requiresDecommission, Boolean instanceRequired, Burden& burden)
at Castle.MicroKernel.Handlers.ExtendedHandler.InvokeResolvePipeline(Int32 extensionIndex, ResolveInvocation invocation)
at Castle.MicroKernel.Handlers.ExtendedHandler.<>c__DisplayClass6.<InvokeResolvePipeline>b__5()
at Castle.MicroKernel.Handlers.ResolveInvocation.Proceed()
at Castle.MicroKernel.Handlers.ComponentLifecycleExtension.Intercept(ResolveInvocation invocation)
at Castle.MicroKernel.Handlers.ExtendedHandler.InvokeResolvePipeline(Int32 extensionIndex, ResolveInvocation invocation)
at Castle.MicroKernel.Handlers.ExtendedHandler.Resolve(CreationContext context, Boolean instanceRequired)
at Castle.MicroKernel.Handlers.AbstractHandler.Resolve(CreationContext context)
at Castle.MicroKernel.Resolvers.DefaultDependencyResolver.ResolveFromKernelByType(CreationContext context, ComponentModel model, DependencyModel dependency)
at Castle.MicroKernel.Resolvers.DefaultDependencyResolver.ResolveFromKernel(CreationContext context, ComponentModel model, DependencyModel dependency)
at Castle.MicroKernel.Resolvers.DefaultDependencyResolver.ResolveCore(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
at Castle.MicroKernel.Resolvers.DefaultDependencyResolver.Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
at Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.ObtainPropertyValue(CreationContext context, PropertySet property, IDependencyResolver resolver)

I've tried adding the Release method to the controller per Windsor's example. I also tried having the factory's Create return an interface instead of a JsonResult. I've tried going through the Windsor source using ILSpy to no avail.

What am I doing wrong? I think I'm following the example pretty closely... is the problem in my code, or in Windsor?

I'm using version 3.2.0 of the various Castle libraries with .Net 4.5.

Upvotes: 6

Views: 2697

Answers (1)

user47589
user47589

Reputation:

Turns out I was installing the facility after registering my factory component. I thought it was before all my components, but I was mistaken. You have to install the facility first. I wrongly expected an exception in AsFactory() if the facility wasn't yet installed.

Here is a complete program that reproduces the issue.

public interface IFooFactory {   IFoo Create();   }
public interface IFoo        {   void DoFoo();    }

public class Foo : IFoo
{
    public void DoFoo()
    {
        Console.WriteLine("I pity the foo");
    }
}

public class Bar
{
    public IFooFactory MyFooFactory { get; set; }

    public void DoBar()
    {
        var foo = MyFooFactory.Create();
        foo.DoFoo();
    }

    static void Main(string[] args)
    {
        var container = new WindsorContainer();
        container.Register(
            Component.For<Bar>().ImplementedBy<Bar>().LifestyleTransient(),
            Component.For<IFoo>().ImplementedBy<Foo>().LifestyleTransient(),
            Component.For<IFooFactory>().AsFactory());
        container.AddFacility<TypedFactoryFacility>();
        var bar = container.Resolve<Bar>();
        bar.DoBar();
    }
}

Upvotes: 11

Related Questions