In this tutorial, you will learn how to do dependency injection within Episerver CMS. With the release of Episerver 7, having a good understanding of dependency injection is critical to making a successful project. Out of the box, Episerver uses StructureMap to handle all the DI required by the CMS. This means that as a developer you don't have to add anything yourself to get started with DI in Episerver CMS. Happy days 😊. Even though you do not need to install anything, you will need to do some configuration tweaks. If you want to learn about these tweaks, read on 🔥🔥🔥
NOTE:: This guide was written for Structure map 2, so you may find some things have changed if you use V3
The Dependency Resolver
The first step towards getting Structure Map configured within your solution is to define a Structure Map dependency resolver class. I used to create this anywhere in my project file. I recommend you avoid adding any code to the App_Code
folder as it won't get compiled correctly 😕. The code to create the resolver is shown below:
Configuring Structure Map
After we have the dependency resolver set up, the next thing to do is to configure Structure Map. This is done by adding a configurable module to your project. A configurable module is like an Episerver initializable module, it will run on start-up. The job of this module will be to tell Episerver how to resolve dependencies. To make a configurable module, create a class and implement from the IConfigurableModule
interface. In this class you will need to implement the ConfigureContainer()
method. Within ConfigureContainer()
we can map our dependencies, giving instructions how the application can map a request for an interface and map it to a concrete class. We set the dependency resolver to use the custom class we created above:
If you do not do this then structure map won't resolve correctly. Next, we need to add in the custom mappings:
Here we can use the ConfigurationExpression
API to add in custom mappings. This code tells the application that whenever it sees a request for an IEpiserverDependenciesResolver
in a constructor, new up an instance of a class of type EpiserverDependenciesResolver
. As long as I had a class of EpiserverDependenciesResolver
within my project with a parameterless constructor, Episerver would auto-populate IEpiserverDependenciesResolver
for me with a new object of type EpiserverDependenciesResolver
💥
The great thing about this approach and DI is that it makes unit testing your code a lot easier.
Configuring Structure Map
The code to register a mapping within Structure Map looks like this:
This code is also equivalent to this code:
After you add a mapping, it should resolve automatically for you. If you make a typo or forget to register a dependency correctly then when your site loads, you'll get this exception:
StructureMap Exception Code: 202 No Default Instance defined for IClass
Whenever you see this, look in your dependency mappings section and make sure your definition is correct. In your example, the value IClass
will be swapped with the dependency with the issue. Another error you might encounter is this one:
An exception of type 'EPiServer.ServiceLocation.ActivationException' occurred in EPiServer.Framework.dll but was not handled in user code
As seen in the screenshot:
If you encounter this error, look at the mapping code!
Dealing With Constructor Parameters
So far we've talked about dependencies in your solution that have a parameterless constructor. What happens if you had the following class:
When the class you want to resolve has constructor arguments, you'll also need to add these extras to the mapping:
On Lines 2 & 3, I define the two constructor parameters that the class EpiserverDependenciesResolve
r depends on, using Ctor
. The first example is a simple interface to a concrete class mapping. I've used an alternative method for the second example to show the different ways you can configure Structure Map. You can manually add the parameter name as a string value within the Ctor
method, however, as this isn't type-safe I wouldn't recommend it. When you define constructor parameters you can also use the IsTheDefault()
method, like this:
Using IsTheDefault()
is the approach that I would recommend as it involved less code. If you have an interface called IClass
and you have a class called Class
, when you use IsTheDefault()
Structure Map will try and automatically figure everything out for you.
Episerver Goodies
Episerver also provides some other useful goodies for dependency resolving. If you create a selection factory or an attribute, then the underlining class will not allow you to inject anything via the constructor. In these scenarios, if you still want to write testable code you can use the Injected
property like this:
Injected
allows you to do property injection rather than constructor injection. In the code above, when the class loads Structure Map will auto-populate the property epiServerDependencies
. This can be really handy in the rare instances when you can't use constructor injection.
Auto Configuration
As developers, we want to write the least amount of code possible. Defining all these mappings can be tedious at times. Luckily, Structure Maps provides an automatic resolver that can prevent you from manually having to write mappings 😊. The code to do this is shown below:
If you add this code into your project when StructureMap first loads it will scan the bin directly. For all interfaces defined in the current assembly, it will try to apply a default mapping rule. The WithDefaultConventions
part means that if structure maps find an interface called IClass
and it can find a class called Class
that implements the IClass
interface, it will automatically register Class
as the default mapping class. Using this approach will save you a lot of time as you can get away without a lot of additional configuration 💥
Below shows a complete IConfigurableModule
you can simply copy and paste into your solution.
That pretty much sums up everything you need to know about Structure Map and Episerver CMS to get you up and running. Happy Coding 🤘