8

I'm trying to setup Castle Windsor for Dependency Injection in Sitecore 8.2 Solution which is using Glass Mapper v4. As noted, Castle Windsor is no longer part of Glass Mapper, and thus not included. I added it manually, and have setup the Installer, the Windsor Controller Factory, and the Pipeline Initializer for Sitecore

The Windsor Controller Factory:

namespace Web.Plumbing
{
    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);
        }
    }
}

The Installer:

namespace Web.Installers
{
    public class ControllersInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            Sitecore.Diagnostics.Log.Info("Windsor installer got registered", this);

            container.Register(Classes.FromThisAssembly().BasedOn<IController>().LifestyleTransient());

            container.Register(Component.For<IService>().ImplementedBy<CommonService>());

        }


    }
}

The Pipeline to Initialize:

namespace Web.Pipelines
{
    public class InitializeWindsorControllerFactory
    {
        public void Process(PipelineArgs args)
        {
            IWindsorContainer container = new WindsorContainer().Install(FromAssembly.This());
            IControllerFactory controllerFactory = new WindsorControllerFactory(container.Kernel);
            SitecoreControllerFactory sitecoreControllerFactory = new SitecoreControllerFactory(controllerFactory);
            System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(sitecoreControllerFactory);
        }


    }
}

And finally, the config to add to pipeline (I just incidentally used glass mapper's patch file to see if it would work)

My Controller is setup as such:

namespace Web.Areas.CastleTest.Controllers
{
    public class TestController : Controller
    {
        ISitecoreContext _context;
        ISitecoreService _master;
        IService _service;

        public ActionResult Index()
        {
            return View();
        }

        public TestController(IService srv, ISitecoreContext context, ISitecoreService service)
        {
            _service = srv;
            _context = context;
            _master = service;
        }




        public ActionResult CtrlTest()
        {
            var model = _context.GetItem<TestTemplate>(RenderingContext.CurrentOrNull.Rendering.DataSource);

            return View(model);
        }
    }
}

The files are definitely getting patched, and the controller factory is definitely getting initialized. The error I am getting is:

[MissingMethodException: Constructor on type 'Web.Areas.CastleTest.Controllers.TestController' not found.]
   System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark) +1481
   System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) +191
   System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture) +27
   Sitecore.Mvc.Helpers.TypeHelper.CreateObject(Type type, Object[] parameters) +44
   Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateControllerInstance(RequestContext requestContext, String controllerName) +213
   Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateController(RequestContext requestContext, String controllerName) +96

I have the feeling that Sitecore is not using WindsorControllerFactory to resolve the controllers. I know there are other ways to replace the default DI container in 8.2, but I need to use the pipeline for now, because I am really trying to debug this for another solution.

4
  • Looking at the stacktrace, your Dependency Resolver is not set properly. Have you injected the Windsor Dependency Resolver into Sitecore Dependency Resolver? Check this link from Dylan
    – phani
    Dec 19, 2016 at 10:08
  • Just an FYI, you're better not to use Castle Windsor in 8.2, as it's not very performant, has scoping issues, and it's so much simpler to just use Sitecore's out-of-the-box DI instead. Jan 13, 2017 at 3:54
  • @SeanHolmesby - I agree!! I don't really use it much anyway, but had to debug a solution that was using it, and had to really find out how it works...:-/
    – M.R.
    Jan 18, 2017 at 21:13
  • @SeanHolmesby, do you have any further info on this? I am experiencing a similar issue.
    – user1704
    Oct 18, 2017 at 7:22

1 Answer 1

2

@phani was right in his comment.

In the Sitecore 8.1 + the Dependency Resolver is used instead of the controller factory.

So, basically you have to set the Default dependency resolver to be the one using castle container.

This is how you define the Castle Dependency Resolver:

public class WindsorDependencyResolver : IDependencyResolver
{
    private readonly IWindsorContainer container;

    public WindsorDependencyResolver(IWindsorContainer container)
    {
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        return container.Kernel.HasComponent(serviceType) ? container.Resolve(serviceType) : null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return container.Kernel.HasComponent(serviceType) ? container.ResolveAll(serviceType).Cast<object>() : new object[]{};
    }
}

After that, you should register your dependency resolver like that:

System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = 
                                    new WindsorDependencyResolver(container);

That should work.

1
  • You may also need to set System.Web.Mvc.DependencyResolver as well, as it's the MVC Dependency Resolver, and the above one only refers to the WebAPI one. Also, ensure you set them BEFORE the Sitecore Dependency Resolver, as the Sitecore one has a fallback to what was set previously (yours). This processor is Sitecore.Mvc.Pipelines.Loader.InitializeDependencyResolver, Sitecore.Mvc Jan 13, 2017 at 4:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.