I am using Castle.Windsor on my project which based on Helix principle. Where the best place to initialize IoC in Helix?
Where I should register container? Foundation/Project layer(Common project or for each project in project layer)
I wrote a blog post on this here - here are the cliff notes.
I'm going to assume Sitecore 8.2 for the version here, but the process is pretty much the same for earlier versions too, there would be some small tweaks.
If you want to use your own container with 8.2 instead of the Sitecore out of the box one, or if this is pre 8.2 you should create a new custom pipeline for it.
Create a new Foundation project, I called it Sitecore.Foundation.DependencyInjection
, then create a new pipeline. I have called the pipeline IntializeDependencyInjection
- this can be kicked off in the initialize
pipeline. Patch it before the InitializeControllerFactory
in 8.2
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<initialize>
<processor type="Sitecore.Foundation.DependencyInjection.Pipelines.Initialize.InitializeDependencyInjection, Sitecore.Foundation.DependencyInjection"
patch:before="processor[@type='Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc']" />
</initialize>
</pipelines>
</sitecore>
</configuration>
The pipeline makes use of the IServiceCollection
interface from the new MS DI Abstractions. This allows us to register our dependencies in the collection from our projects without having to put a dependency on the container in the projects. It also means we stick closer to the CompositionRoot pattern for registering the dependencies.
The pipeline needs custom args to pass the IServiceCollection
around:
namespace Sitecore.Foundation.DependencyInjection.Pipelines.InitializeDepdencyInjection
{
using Microsoft.Extensions.DependencyInjection;
using Sitecore.Pipelines;
public class InitializeDependencyInjectionArgs : PipelineArgs
{
public IServiceCollection ServiceCollection { get; set; }
public InitializeDependencyInjectionArgs(IServiceCollection serviceCollection)
{
this.ServiceCollection = serviceCollection;
}
}
}
Now run the pipeline and pass the args around. Once the pipeline has finished, you will have a populated collection of registrations. So you need to run through that and register each one with your container. It looks like CastleWindsor has a conforming container so you can populate the container with the IServiceCollection
namespace Sitecore.Foundation.DependencyInjection.Pipelines.Initialize
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Microsoft.Extensions.DependencyInjection;
using SimpleInjector;
using SimpleInjector.Integration.Web.Mvc;
using Sitecore.Diagnostics;
using Sitecore.Foundation.DependencyInjection.Pipelines.InitializeDepdencyInjection;
using Sitecore.Pipelines;
public class IntializeDependencyInjection
{
public void Process(PipelineArgs args)
{
Log.Info("Start dependency injection initialization", this);
var serviceCollection = new ServiceCollection();
// start the pipeline to register all dependencies
var dependencyInjectionArgs = new InitializeDependencyInjectionArgs(serviceCollection);
CorePipeline.Run("initializeDependencyInjection", dependencyInjectionArgs);
var container = new WindsorContainer();
WindsorRegistration.Populate(container, services, app.ApplicationServices);
var sp = container.Resolve<IServiceProvider>();
// TODO: Set the ASP.NET dependency resolver
}
}
}
NOTE* this part is untested and you still have to set the dependency resolver - I'm not familiar with how to do that using CastleWindsor.
Finally you need to add processors to the pipeline to register your dependencies for the features. Create a new processor, call it RegisterServices
, use the InitializeDependencyInjectionArgs
that you created above:
public class RegisterServices
{
public void Process(InitializeDependencyInjectionArgs args)
{
args.ServiceCollection.AddTransient<IAccountRepository, AccountRepository>();
// TODO: Add any other registrations here
args.ServiceCollection.AddMvcControllersInCurrentAssembly();
}
}
Then register your dependencies for that feature - you would create one of these for each feature/foundation or even project that you have in your solution.
Add the processor to your feature/foundation projects config:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<initializeDependencyInjection>
<processor type="Sitecore.Feature.Accounts.Pipelines.InitializeDependencyInjection.RegisterServices, Sitecore.Feature.Accounts" />
</initializeDependencyInjection>
</pipelines>
</sitecore>
</configuration>
So the cliff notes turned into a bit of a long post, but that should give you a good place to start.