• Publisert
  • 3 min

Injecting stuff in your view controller

The ServiceLocator is nice and real handy, but wouldn’t it be nice to get dependency injection right there in your controller’s constructor?

I need data. I need to use some sort of data provider in my controller class. So, should I use DataFactory.Instance, ServiceLocator.Current.GetInstance<IContentRepository>(), new up a ServiceLocationHelper in my controller base class or inject an implementation of IContentRepository in my controller’s constructor? All these solutions solve my immediate problem, but I would like a permanent and easily testable solution.

Using the ServiceLocator seems at first to be the most modern and flexible solution. It is what DataFacory.Instance is using behind the scenes (I’m guessing) and it is kind of testable even though it is static and does not have a testable look and feel to it. I can create a mock of IServiceLocator and pass it along to the static ServiceLocator.SetLocator method in all my tests and start mocking the usage of ServiceLocator.Current.GetInstance<Whatever>(), but then I would have to know all about which services my class under test is fetching instances of. I would like dependency injection in my controller constructor instead.

Requirements

  • I need to be able to define rules for resolving my dependencies in code.
  • I don’t want to include an additional library – so I’ll have to use StructureMap; EPiServer’s DI/IoC library of choice.
  • These rules has to be an addition to EPiServer’s own rules (EPiServer tells StructureMap quite a bit about resolving stuff on application start-up) so I cannot overwrite anything.
  • I need to be able to inject dependencies in controller constructors.
  • I need to be able to use the same ServiceLocator.Current for all instance fetching if I need to. Fetching EPiServer stuff, like IContentRepository and my own interface implementations in the same way.

A little help

The solution I’m about to describe came to me via the forums. Thanks to Sergii Vorushylo and Jonas Bergqvist  for the pointers.

A dependency resolver

The first thing to implement is a StructureMap dependency resolver:

public class StructureMapDependencyResolver : IDependencyResolver
{
  private readonly IContainer container;

  public StructureMapDependencyResolver(IContainer container)
  {
    this.container = container;
  }

  public object GetService(Type serviceType)
  {
    if (serviceType.IsInterface || serviceType.IsAbstract)
      return GetInterfaceService(serviceType);

    return GetConcreteService(serviceType);
  }

  public IEnumerable<object> GetServices(Type serviceType)
  {
    return container.GetAllInstances(serviceType).Cast<object>();
  }

  private object GetConcreteService(Type serviceType)
  {
    return container.GetInstance(serviceType);
  }

  private object GetInterfaceService(Type serviceType)
  {
    return container.TryGetInstance(serviceType);
  }
}

In addition I will be needing a configurable module (not an initializable module, mind you. I need the configuration context of the ConfigureConatiner method) to tell StructureMap, MVC and EPiServer how to resolve dependencies:

[ModuleDependency(typeof(ServiceContainerInitialization))]
public class MvcDependencyResolverModule : IConfigurableModule
{
  private IContainer container;

  public void ConfigureContainer(ServiceConfigurationContext context)
  {
    container = context.Container;
    DependencyResolver.SetResolver(
      new StructureMapDependencyResolver(context.Container));
  }

  public void Initialize(InitializationEngine context)
  {
    StructureMapConfiguration.Configure(container);
  }

  public void Preload(string[] parameters)
  {
  }

  public void Uninitialize(InitializationEngine context)
  {
  }
}

This class calls upon a configuration class that fluently defines the rules for resolving my custom dependencies:

public class StructureMapConfiguration
{
  public static void Configure(IContainer container)
  {
    container.Configure(
      x =>
      {
        x.For<IProvideAwesomeness>().Use<AwesomeStuff>();
      });
  }
}

This sample resolves only one dependency to prove the point, but you can of course add many more using the same syntax.

Summary

So, with these things in place I can inject stuff in my controller classes via the constructor – my own interface implementations and EPiServer’s mixed and matched. I can create specific mocks for those dependencies when testing. I can also use the ServiceLocator.Current to get instances if my own classes/interfaces as well as EPiServer’s if I need a service outside the view controller context. It feels right.