Inversion of Control and dependency management with Sitecore configuration factory

Today, when we talk about modern software application development, its quite obvious that using Inversion of Control (IoC) design principle is a must have. Having ability to change dependencies of the component without changing the component itself is very important for any kind of application I think.

When you creating a Sitecore website you still can use one of the IoC frameworks and there are an amazing number of them today available. First link in google gives me this post with the list and that is only a small part of existing frameworks.

Having them in your solution is great, but what if you are creating a Sitecore module or a nuget package? That is the case where you need to provide a decent level of extensibility so your module can be re-used, extended, and changed on client side if needed (by client side I mean the solution which uses your module).

In the same time it needs to be de-coupled enough so the IoC principle is still a must have here but there are some limitations:

  • You can’t really use one of those frameworks because you don’t want solution which uses your module to depend on a specific IoC framework
  • Actually you don’t really want your module to depend on any specific IoC framework
  • You need to declare a list of dependencies and instructions on how to register them in the IoC container so your module runs properly

Using Sitecore configuration factory to handle dependencies

This is not a new feature or approach but recently I found out for myself a nice out-of-the-box feature of Sitecore which helps with the dependency management. And that is a default Sitecore.Configuration.Factory.
Here are some links about it:

For start will bring an example of configuring one of my Helpfulcore modules – the logging service.
I have an abstracted logging service which can contain a number of logging providers to write to and they are being injected via constructor:

// source from https://github.com/vhil/helpfulcore-logging/blob/master/Sources/Helpfulcore.Logging/LoggingService.cs
public class LoggingService : ILoggingService
{
	private readonly ILoggingProvider[] loggingProviders;

	public LoggingService(ILoggingProvider provider)
		:this(new []{provider})
	{
	}

	public LoggingService(ILoggingProvider provider1, ILoggingProvider provider2)
		:this(new[] { provider1, provider2 })
	{
	}

	public LoggingService(params ILoggingProvider [] providers)
	{
		this.loggingProviders = providers;
	}
	...
}

And there are two implementations of ILoggingProviders

And now I want to configure a global logging service for my website to use both logging providers. I create a configuration inside default configuration node using include config files so resulting config looks like this:

<sitecore>
  <helpfulcore>
    <logging>
      <loggingService type="Helpfulcore.Logging.LoggingService, Helpfulcore.Logging" singleInstance="true">
        <param name="provider1" ref="helpfulcore/logging/providers/scLoggingProvider"/>
		<param name="provider2" ref="helpfulcore/logging/providers/nlogLoggingProvider"/>
      </loggingService>
      <providers>
	    <scLoggingProvider type="Helpfulcore.Logging.Sc.ScLoggingProvider, Helpfulcore.Logging.Sc" singleInstance="true"/>
        <nlogLoggingProvider type="Helpfulcore.Logging.NLog.NLogLoggingProvider, Helpfulcore.Logging.NLog" filePath="$(dataFolder)/logs/Website.log.${date:format=yyyyMMdd}.txt" singleInstance="true">
          <param name="filePath">$(filePath)</param>
        </nlogLoggingProvider>
      </providers>
    </logging>
  </helpfulcore>
</sitecore>

So there are two providers configured in the section and they are being passed as “ref” attributes into the loggingService as constructor parameters. Im my code now I can get the instance of the logging service just by calling the configuration factory method:

var loggingService = Factory.CreateObject("helpfulcore/logging/loggingService", true) as ILoggingService;

This call will resolve all related dependencies as described in the config and create all configured instances including “singleInstance” lifestyle if declared. Also I can register this instance in my IoC container for my Sitecore website;

container.Register(
		typeof(ILoggingService),
		() => Factory.CreateObject("helpfulcore/logging/loggingService", true) as ILoggingService,
	Lifestyle.Singleton);

Okay. Now I want to implement a service which uses the logging service and injects it as a dependency.  so it can write to log about its actions. So I create a service

public class MyService : IMyService
{
	protected readonly ILoggingService Logger;

	public MyService(ILoggingService logger)
	{
		this.Logger = logger;
	}
	...
}

The key point in all of that is having control under your dependency injections. I am used to inject everything via constructor and MyService implementation here has a constructor dependency on ILoggingService. What I do next is I am creating configuration for it in the sitecore include file:

<sitecore>
  <myFeature>
	  <myService type="MyNamespace.MyService, MyAssembly">
		<param name="logger" ref="helpfulcore/logging/loggingService"/>
	  </myService>
  </myFeature>
</sitecore>

And now I can get an instance of it from the factory method with default logging service being injected:

var myService = Factory.CreateObject("myFeature/myService", true) as IMyService;

That’s it. It all looks and works great now. But at some point I can decide that ok, I want my service to write to its own log file so I can monitor its actions in a more readable way. So what I can do now is to just change the config file by configuring new instance of logging service with one dedicated provider which writes to MyService.log.${date:format=yyyyMMdd}.txt log file and changing the logger reference in myService configuration node.

<sitecore>
  <myFeature>
    <myService type="MyNamespace.MyService, MyAssembly">
      <param name="logger" ref="myFeature/logging/loggingService"/>
    </myService>
    <logging>
      <loggingService type="Helpfulcore.Logging.LoggingService, Helpfulcore.Logging" singleInstance="true">
        <param name="provider1" ref="myFeature/logging/providers/nlogLoggingProvider"/>
      </loggingService>
      <providers>
        <nlogLoggingProvider type="Helpfulcore.Logging.NLog.NLogLoggingProvider, Helpfulcore.Logging.NLog" filePath="$(dataFolder)/logs/MyService.log.${date:format=yyyyMMdd}.txt" singleInstance="true">
          <param name="filePath">$(filePath)</param>
        </nlogLoggingProvider>
      </providers>
    </logging>
  </myFeature>
</sitecore>

No code changes required, all dependencies are controlled in config files and its really simple to use.

Configure Fortis as an example

As a separate example I can configure the Fortis framework  in the include config file. Fortis framework is all built on constructor dependency injection approach so that will be quite simple for me now.

<sitecore>
  <fortis>
    <itemFactory type="Fortis.Model.ItemFactory, Fortis" singleInstance="true">
      <param name="contextProvider" ref="fortis/dependencies/contextProvider" />
      <param name="spawnProvider" ref="fortis/dependencies/spawnProvider" />
    </itemFactory>
    <spawnProvider type="Fortis.Providers.SpawnProvider, Fortis" singleInstance="true">
      <param name="templateMapProvider" ref="fortis/dependencies/templateMapProvider" />
    </spawnProvider>
    <templateMapProvider type="Fortis.Providers.TemplateMapProvider, Fortis" singleInstance="true">
      <param name="modelAssemblyProvider" ref="fortis/dependencies/modelAssemblyProvider" />
    </templateMapProvider>
    <modelAssemblyProvider type="Fortis.Providers.ModelAssemblyProvider, Fortis" singleInstance="true"/>
    <itemSearchFactory type="Fortis.Search.ItemSearchFactory, Fortis" singleInstance="true">
      <param name="templateMapProvider" ref="fortis/dependencies/templateMapProvider" />
      <param name="searchResultsAdapter" ref="fortis/dependencies/searchResultsAdapter" />
    </itemSearchFactory>
    <searchResultsAdapter type="Fortis.Search.SearchResultsAdapter, Fortis" singleInstance="true"/>
    <contextProvider type="Fortis.Mvc.Providers.ContextProvider, Fortis.Mvc" singleInstance="true"/>
  </fortis>
</sitecore>

As described in documentation I need to initialize the Fortis.Global factory class on the application start with three instances so I do it like this:

Global.Initialise(
	Factory.CreateObject("fortis/spawnProvider", true) as ISpawnProvider,
	Factory.CreateObject("fortis/itemFactory", true) as IItemFactory,
	Factory.CreateObject("fortis/itemSearchFactory", true) as IItemSearchFactory
);

And I still can do the same for my IoC if I use one.
Pretty amazing feature and its all a default Sitecore functionality.

Helpfulcore

Talking about “helpfulcore” term referenced above – it became my “pet” project collection for small features that I use from project to project. They all are nuget packages except the Wildcard module.
Will share the list in case you may be interested in using them, for me they are just helpful (read from the name lol :))

Will keep you updated if any new helpful module appears in my collection.
Thanks for reading, now go and implement something amazing! 🙂

Advertisements

One thought on “Inversion of Control and dependency management with Sitecore configuration factory

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s