Setup Castle Windsor in MVC
Asked Answered
B

2

6

I'm trying to setup Castle Windsor for the first time and I'm having some problems with it. I have three projects in my solution:

  • Domain
  • DAL
  • Web

The services are located in DAL. They all inherit from IService. (UserService implements IUserService, IUserService implements IService). The web application is an MVC 5 application. All Controllers inherit from BaseController.

I used this post to help me setup Windsor but I keep getting the exception:

An exception of type 'Castle.MicroKernel.ComponentNotFoundException' occurred in Castle.Windsor.dll but was not handled in user code

Additional information: No component for supporting the service Solution.Web.Controllers.HomeController was found

The strange thing is that the path for the controller is correct.

Below is my code for the configuration:

public class WindsorControllerFactory : DefaultControllerFactory
{
  private readonly IKernel kernel;

  public WindsorControllerFactory(IKernel kernel)
  {
    this.kernel = kernel;
  }

  public override void ReleaseController(IController controller)
  {
    kernel.ReleaseComponent(controller);
  }

  protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
  {
    if (controllerType == null)
    {
      throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
    }
    return (IController)kernel.Resolve(controllerType);
  }
}

public class ControllersInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
          Classes.FromThisAssembly()
          .BasedOn(typeof(BaseController))
          .LifestyleTransient());
    }
}

public class ServiceInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Types.FromAssemblyContaining(typeof(IService).GetType())
            .BasedOn<IService>().WithService.FromInterface()
            .LifestyleTransient()
        );
    }
}

And in the Global.asax:

public class MvcApplication : System.Web.HttpApplication
{

    private static IWindsorContainer container;

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        // Setup Castle.Windsor IOC
        MvcApplication.BootstrapContainer();
    }
    protected void Application_End()
    {
        container.Dispose();
    }

    private static void BootstrapContainer()
    {
        container = new WindsorContainer().Install(FromAssembly.This());
        container.Install(FromAssembly.Containing(typeof(IService).GetType()));
        var controllerFactory = new WindsorControllerFactory(container.Kernel);
        ControllerBuilder.Current.SetControllerFactory(controllerFactory);
    }
}

Any help or guidance in the right direction is greatly appreciated!

Bijouterie answered 2/11, 2013 at 14:52 Comment(0)
B
9

I made it work. Apperantly the problem was that my services didn't get registered. I changed the ServiceInstaller and the registration in Global.asax.

public class ServiceInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromAssemblyContaining<BaseService>()
            .BasedOn(typeof(IService))
            .WithService.AllInterfaces()
            .LifestyleTransient());            
    }
}

private static void BootstrapContainer()
{
    container = new WindsorContainer();
    container.Install(new ServiceInstaller());
    container.Install(new ControllersInstaller());

    var controllerFactory = new WindsorControllerFactory(container.Kernel);
    ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
Bijouterie answered 3/11, 2013 at 0:57 Comment(2)
Cool glad it works now. Did you end up having to change your controller registration at all?Willow
Nope the registration of the controller was correct. Thanks again for the tips and the explaination!Bijouterie
W
11

I'm assuming it's blowing up here:

return (IController)kernel.Resolve(controllerType);

What you're asking castle to do here in English is "give me the component that implements a service defined by controllerType".

The problem comes in your registration of your controllers.

container.Register(
      Types.FromThisAssembly()
      .BasedOn(typeof(BaseController))
      .WithServices(typeof(BaseController))
      .LifestyleTransient());

In this block you are telling castle to register all of your types that implement BaseController and the services they are exposing is also BaseController.

So castle is looking for a component that satisfies the service HomeController and can't find anything because the only service you've got is BaseController.

Long story short, if you remove

.WithServices(typeof(BaseController))

Castle will assume that each of your controllers is a service and then you can ask for components that implement your controller in the way that you want.

As a separate note, for clarity I'd change Types.FromThisAssembly() to Classes.FromThisAssembly() because you are only looking for classes, not stucts/classes/interfaces, etc that Types will scan for.

Willow answered 2/11, 2013 at 17:38 Comment(1)
I've made the changes that you suggested but I keep getting the same error. Thank you for the detailed explanation of Castle :)Bijouterie
B
9

I made it work. Apperantly the problem was that my services didn't get registered. I changed the ServiceInstaller and the registration in Global.asax.

public class ServiceInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromAssemblyContaining<BaseService>()
            .BasedOn(typeof(IService))
            .WithService.AllInterfaces()
            .LifestyleTransient());            
    }
}

private static void BootstrapContainer()
{
    container = new WindsorContainer();
    container.Install(new ServiceInstaller());
    container.Install(new ControllersInstaller());

    var controllerFactory = new WindsorControllerFactory(container.Kernel);
    ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
Bijouterie answered 3/11, 2013 at 0:57 Comment(2)
Cool glad it works now. Did you end up having to change your controller registration at all?Willow
Nope the registration of the controller was correct. Thanks again for the tips and the explaination!Bijouterie

© 2022 - 2024 — McMap. All rights reserved.