Sitecore and SimpleInjector issues with WFFM

I am using Simple Injector as an IoC framework on my Sitecore pojects. And what I faced recently is that Sitecore modules like FXM, WFFM do not work properly.
The reason of that is the default Simple Injector implementation regarding constructor resolution behavior. Lots of Sitecore classes like Controllers implemented the way that they have multiple constructors.
Out of the box, Simple Injector only allows the creation of classes that contain a single public constructor. They explain this as having multiple constructors is an anti-pattern and I agree.

While creating a container and registering types in it I usually register MVC controllers as well to be able to inject dependencies into them by setting the resolver to the default MVC DependencyResolver class.
This means that Sitecore controllers within my solution now are being instantiated by IoC container. When any of them have multiple constructors the Simple Injector throws exception as it can’t instantiate those.
It was quite confusing situation when I installed few Sitecore modules and they just didn’t work as expected and took a while to figure out.

Fortunately there is a solution for that. We can implement a custom constrctor resolution behavior. There are more ways to do that but here is what I use. This class will try to find the most resolvable constructor in the class that is being instantiated. If anything wrong it will just fallback to default “single constructor behavior”.

using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using SimpleInjector;
using SimpleInjector.Advanced;

public class MostResolvableConstructorBehavior : IConstructorResolutionBehavior
{
	private readonly Container container;
	private readonly IConstructorResolutionBehavior fallbackBehavior;

	public MostResolvableConstructorBehavior(Container container)
	{
		this.container = container;
		this.fallbackBehavior = container.Options.ConstructorResolutionBehavior;
	}

	private bool IsCalledDuringRegistrationPhase
	{
		get { return !this.container.IsLocked(); }
	}

	public ConstructorInfo GetConstructor(Type service, Type implementation)
	{
		var constructors = implementation.GetConstructors();

		if (!constructors.Any())
		{
			return this.fallbackBehavior.GetConstructor(service, implementation);
		}

		return constructors.Select(ctor => new { ctor, parameters = ctor.GetParameters() })
				.Where(type => this.IsCalledDuringRegistrationPhase
					|| constructors.Length == 1
					|| type.parameters.All(p => this.CanBeResolved(p, service, implementation)))
				.OrderByDescending(type => type.parameters.Length)
				.Select(type => type.ctor)
			.First();
	}

	private bool CanBeResolved(ParameterInfo p, Type service, Type implementation)
	{
		return this.container.GetRegistration(p.ParameterType) != null || this.CanBuildType(p, service, implementation);
	}

	private bool CanBuildType(ParameterInfo p, Type service, Type implementation)
	{
		try
		{
			this.container.Options.DependencyInjectionBehavior.BuildExpression(new InjectionConsumerInfo(service, implementation, p));
			return true;
		}
		catch (ActivationException)
		{
			return false;
		}
	}
}

And now we just need to do this while initializing the container:

container.Options.ConstructorResolutionBehavior = new MostResolvableConstructorBehavior(container);

So my initializer class looks like this:

using System.Web.Mvc;
using SimpleInjector;
using SimpleInjector.Integration.Web.Mvc;
using Sitecore.Pipelines;

namespace Website
{
	public class DependencyInjectionInitializer
	{
		public void Process(PipelineArgs args)
		{
			Initialize();
		}

		public static void Initialize()
		{
			var container = new Container();
			
			// Change the consturctor resolution behavior here
			container.Options.ConstructorResolutionBehavior = new MostResolvableConstructorBehavior(container);
			
			// Register all solution related types
			RegisterWebsiteTypes(container);
			
			container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
			container.RegisterMvcIntegratedFilterProvider();

			// Register the container as MVC IDependencyResolver.
			DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
        }

		private static void RegisterWebsiteTypes(Container container)
	    {
            // container.Register<ISitecoreContext, SitecoreContext>(Lifestyle.Transient);
			// ...
		}
	}
}

If that’s unclear, I initialize the container in the ‘initialize’ Sitecore pipeline by having next config:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <initialize>
        <processor type="Website.DependencyInjectionInitializer, Website" />
      </initialize>
    </pipelines>
  </sitecore>
</configuration>

This solution works for me now, all modules came back to normal working, but still need to test that more lol 🙂
Hope it was helpful 🙂

Advertisements

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