In this tutorial, you will learn about dependency injection within Episerver. You will learn about a technique that may help you write cleaner code. You will also helpfully learn a little bit about the CMS and how it has improved over the years.
Trying to get 100% test coverage in your project is a noble goal. In Episerver 6 trying to get good test coverage was difficult. The main way to access page data was via the DataFactory API. Trying to test code that used
DataFactory was difficult. The
DataFactory was implemented using a static helper that followed the singleton pattern. The
DataFactory was difficult to mock. The
DataFactory also relied on the HTTP context to exist. Without the correct context, the
DataFactory would throw a
NullReference whenever it was accessed within a test.
The key to writing tests is to inject all the dependencies required by a class instead of instantiating them directly. In simple terms, you can not use the
new keyword anywhere in your class. Instead, you will need to inject all your dependencies through the constructor as a parameter. This is why the way in which you access the APIs changed within Episerver 7. This change in API access makes for more flexible architectures. Two APIs that come with Episerver 7 are the
IContentRepository and the
ILinkResolver. You can access
ILinkResolver like this:
This code uses a service locator to get access to the API. Service location is considered a bad technique. Instead, you should access an API using constructor injection, like so:
When you start injecting dependencies like this, sooner or later you will run into the problem of injecting too many items.
One way to elevate this parameter overload is to group related dependencies using the facade pattern. In this example, I will create a facade called
EpiserverDependencies. My class will now look like this:
What this code is doing is passing in an 'IContentRepositoryFactory' and 'ILinkResolverFactory'. These are two custom factories that I have created that will create the Episerver dependencies. I also use
Lazy to store the
ILinkResolver. If you have never come across
Lazy it allows you to only instantiate something the first time it is actually used. As this class will be passed into every base controller (read on for explanation), we do not want to instantiate everything on every request. The dependencies might not be used on each page request so delaying the load saves processing time and improves performance.
Now we have a class that will make it possible to unit test our code simpler. The next question is, how do we actually this class within a website? The first thing you need to do is inject your dependencies into your website. Episerver comes with Structure Map out-of-the-box. THe code to do this, would look something like this:
Now we have set up Structure Map to inject our base dependencies whenever a call to
IEpiserverDependencies is made. Our next step is to actually start injecting this dependency into a class so we can use it. The starting point for all of your pages will be a controller. In Episerver, one way of structuring your website is to use a base page controller. This allows you to add some common features like your base dependencies and SSL. Below shows you an example of an Episerver base controller:
The next step in this process is to create a corresponding page controller for a page type. In this example, I am going to use an example page called
In the controller, a view model is created and passed down into the view. Some people get confused around the use of a view model when they have the Episerver page object. In my simple opinion, a controller is a place that the routing engine looks for when it's trying to resolve a URL. The controller is responsible for getting the data required by the view, adding caching, authorization, handling query string. The Episerver page object should not contain code that renders presentation data. Data required in the view should be done in a view model. This creates a clean separation of concerns. Now we have that cleared up, let's see what the view model looks like:
A lot of Episoerver sites use a base view model, where an instance of the current page and Episerver dependencies is passed into it to save on code duplication:
We have our dependencies injected into a view model, let us use them in a view:
This is a very small example, however, you can see how it has removed the dependency from Episerver in the controller. If you wanted to unit test this simple method you can now use something like MOQ to mock
That wraps up the first in this series of how to unit tests in Episerver and as of yet, we have yet to write a single test! We have written a mini-framework that will allow you to unit test anything Episerver API used in our code easily and consistently. This is a huge step forward. In the next chapter of this Epi saga, I will show you how you can write tests using fakes or the more popular mocks. The code for the whole of this series can be found on my #ILoveEpiserver project here enjoy :) Happy Coding 🤘