Search code examples
c#asp.net-web-apidependency-injectioncastle-windsorioc-container

Castle Windsor: Controller resolution failing when registration seems to be fine


I have a Web Api project and using Castle Windsor as the IoC. I have done this quite a few times and honestly I cannot understand why this is not working so here goes everything that I am doing:

Controller on the Web Api project: Nothing fancy here

public class TestController : ApiController, ITestController  
{  
...  //Currently with its default constructor.
}

Global.asax

    public class WebApiApplication : System.Web.HttpApplication
    {
        private readonly IWindsorContainer container;

        public WebApiApplication()
        {
            container = new WindsorContainer().Install(FromAssembly.Named("DependenciesConfiguration"));
        }

        protected void Application_Start()
        {
            GlobalConfiguration.Configure(WebApiConfig.Register);
            GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new DiControllerActivator(container));
        }
}

DiControllerActivation class This is the class that is replacing the default controller activator in the Global.asax class.

public class DiControllerActivator : IHttpControllerActivator
{
    private readonly IWindsorContainer container;

    public DiControllerActivator(IWindsorContainer container)
    {
        this.container = Argument.NotNull(container, (nameof(container)));
    }

    public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        //This is the line that fails saying "No component for supporting the service TestController was found.
        var controller = (IHttpController)container.Resolve(controllerType);

        request.RegisterForDispose(new Release(() => container.Release(controller)));

        return controller;
    }
}

internal class Release : IDisposable
{
    private readonly Action release;

    public Release(Action release)
    {
        this.release = release;
    }

    public void Dispose()
    {
        this.release();
    }
}

And finally the Web Services Installer

public class ServicesInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromAssemblyNamed("WebServices")
            .Where(type => type.Name.EndsWith("Controller"))
            .WithService.DefaultInterfaces()
            .Configure(c => c.LifestylePerWebRequest()));
    }
}

What it is really frustrating is that, like I said, I have donde this before, I went to my previous work to see if I was missing anything and I cannot find anything and this has always worked well.

When running the application after the installer runs I can see that the service is in the container and when it fails saying "No component for supporting the service TestController was found" I can still see the service within the container in the Watch Window.

I am using Castle version 4.0

Thank you for any pointers and help.


Solution

  • As it turns out there is a subtle but critical difference in this code from the other times I did this.. The fact that the TestController is implementing an interface and is registered as such messes up the whole thing.

    Since the Create method in the DiActivator class is trying to resolve the controller based on its type and not its default interface the container cannot find it.

    One solution is just to remove the interface from the controller or to add the necessary code in the Create method that gets the default interface of the received type and resolves for it.