7

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)

7

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.

Registering your own IoC Container

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.

InitialiseDependencyInjection Pipeline

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.

Register Your Dependencies in each Feature

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.

  • Nice one Richard. You are right, If we want to use our own container instead of Sitecore's container, then creating our own Pipeline would do the needful. I had tried the same way sometime back while researching for a new project with Helix principles and it had worked. Thanks for sharing the info here. – Varun Shringarpure Mar 1 '17 at 7:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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