This post has been migrated from www.experimentsincode.com, we apologise if some of the images or content is missing

In the first blog in the series I looked at how you could create a commenting component that you could associate with any item in Sitecore. In this post we will look at how we can use IOC to create the controller and inject the services it needs, to do this I will be using Castle Windsor Container. There isn't actually anything special about configuring an IOC for Sitecore's MVC solution since Sitecore delegates the resolution of controllers to the standard .NET MVC implementation. Most of the Windsor code I have taken from Jonathan Creamer's blog. First you need to create a controller factory that uses the IOC container:
    public class WindsorControllerFactory : DefaultControllerFactory
    {
        private readonly IKernel _kernel;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="kernel"></param>
        public WindsorControllerFactory(IKernel kernel)
        {
            _kernel = kernel;
        }

        /// <summary>
        /// Release the controller at the end of it's life cycle
        /// </summary>
        /// <param name="controller">The Interface to an MVC controller</param>
        public override void ReleaseController(IController controller)
        {
            _kernel.ReleaseComponent(controller);
        }

        /// <summary>
        /// Resolve a controller dependency
        /// </summary>
        /// <param name="requestContext">The HTTP context</param>
        /// <param name="controllerType">Type of controller to resolve</param>
        /// <returns>IController</returns>
        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);
        }
    }
For Castle we can create an installer that will search our assembly for controllers:
    public class ControllerInstaller : IWindsorInstaller
    {
        /// <summary>
        /// Installs the controllers
        /// </summary>
        /// <param name="container"></param>
        /// <param name="store"></param>
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(FindControllers().Configure(x => { x.LifestyleTransient(); }));
        }

        /// <summary>
        /// Find controllers within this assembly in the same namespace as HomeController
        /// </summary>
        /// <returns></returns>
        private BasedOnDescriptor FindControllers()
        {
            return AllTypes.FromThisAssembly()
                .BasedOn<SitecoreController>();
        }
    }
Now we just need to update the Application_Start method in out Global.asax file, first we register the Glass configuration:
            //register glass
            Glass.Sitecore.Mapper.Context context = new Glass.Sitecore.Mapper.Context(
                new Glass.Sitecore.Mapper.Razor.GlassModuleLoader(),
                new AttributeConfigurationLoader(
                    "Demo.Templates, Demo",
                    "Demo.Models, Demo"));
Next instantiate the IOC container and configure it with the controllers and services it will need:
            //setup the container
            WindsorContainer container = new WindsorContainer();

            //register the controllers
            container.Install(new ControllerInstaller());

            //register the Glass components
            container.Register(
                Component.For<ISitecoreContext>().ImplementedBy<SitecoreContext>().LifestyleTransient(),
                Component.For<ISitecoreService>().ImplementedBy<SitecoreService>().LifestyleTransient()
                    .DependsOn(Dependency.OnValue<string>("master"))
                );
Finally configure .NET MVC to use our new controller factory;
            //setup the controller factory
            ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container.Kernel));
To test we need to alter the CommentsController class from the first example by removing the default constructor to just leave us with the constructor that handles dependency injection:
    public class CommentController  : SitecoreController
    {
        ISitecoreContext _context;
        ISitecoreService _master;
        
        /// <summary>
        /// This constructor can be used with dependency injection or unit testing 
        /// </summary>
        /// <param name="context"></param>
        public CommentController(ISitecoreContext context, ISitecoreService master) 
        {
            _context = context;
            _master = master;
        }

        [HttpGet]
        public override ActionResult Index()
        {
            var model = _context.GetCurrentItem<CommentPage>();
            return View(model);
        }

        [HttpPost]
        public ActionResult Index(Comment comment)
        {
            

            var webModel = _context.GetCurrentItem<CommentPage>();
            

            if (ModelState.IsValid && comment != null)
            {
                var masterModel = _master.GetItem<CommentPage>(webModel.Id);

                if (masterModel.CommentFolder == null)
                {
                    CommentFolder folder = new CommentFolder();
                    folder.Name = "Comments";

                    using (new SecurityDisabler())
                    {
                        _context.Create(masterModel, folder);
                    }
                    masterModel.CommentFolder = folder;
                }

                using (new SecurityDisabler())
                {
                    comment.Name = DateTime.Now.ToString("yyyyMMddhhmmss");

                    //create the comment in the master database
                    _master.Create(masterModel.CommentFolder, comment);
                    webModel.CommentAdded = true;
                }
            }

           
            return View(webModel);
        }
    }
If we compile the solution and run the page we should find that we get the same result as before.
comments powered by Disqus