There are several problems with Injected<T> and ServiceLocator - mostly they hide the dependencies from outside. Also they make the class almost impossible to test (unless you mess with the service registration, and I can tell you that can be very messy)
I kinda disargee with Scott on 2. point. static helper classes can be useful if they only serve as true "static", i.e. no state. Of course that's when you have to decide between static helper class and singleton, but that's pretty much your taste. If your static helper class does not prevent its consumer classes from being unit tested (mocking etc.) then it's fine for me.
Let me clarify, if a static class just had a load of constants in it or extension methods that's acceptable. But I wouldn't personally want any methods in static classes, I would want them all in services and injected. Our solutions used to be littered with static helpers and they were a mess to test.
Doing dependency injection and making helper classes instead of writing C# code in razor views may seem like overkill to some developers.
However, when developing Episerver solitions, we want to make sure our code works by writing unit tests, in addition to manual testing.
For example, when showing pages in the main navigation, it's not enough to do
_contentLoader.GetChildren<PageData>(ContentReference.StartPage).ToList().
We need to make sure we're not returning:
This is something that developers should test by mocking IServiceLocator, ITemplateResolver, IPublishedStateAssessor etc.
However, unit-testing may be difficult if the business logic is located inside static classes, razor views, etc.
When it comes to mocking ServiceLocator and Injected<T>... it takes just two lines of code:
var serviceLocatorMock = new Mock<IServiceLocator>();
ServiceLocator.SetLocator(serviceLocatorMock .Object);
However, mocking internal episerver stuff can be quite tricky.
there is a trick to avoid ServiceLocator usage in extension methods to get access to the service required. You create extension method on the service. For example, not this:
pageData.GetSomeFancyExtenralUrl(..)
static GetSomeFancyExtenralUrl(this ContentData page, ...)
{
var resolver = ServiceLocator.Current.GetInstance<UrlResolver>();
...
}
but you actually make an extension on `UrlResolver` instead:
resolver.GetSomeFancyExtenralUrl(pageData, ..)
static GetSomeFancyExtenralUrl(this UrlResolver resolver, ContentData page, ...)
{
...
}
and now you just have to solve the issue how you are going to get to the instance of the `UrlResolver` class. usually either you can go with `Injected<T>`, demand in constructor or do any other of the black magic to get access to.
Hi guys,
very simple question,
I had a static helper class that provides for me the Content References for some of the most used pages in the solution.
Then other developer said, let' not use it but create an interface and class implementation with ServiceConfiguration attrubute. And later on use it as a constructor injection to get the instance.
As far as I understand there is nothing wrong in the static helper class when i am not referencing none of the shared variables.. which in my case should not as I only get the references to the instances of the pages..
Where the approach with the dependency injection seems to me an overkill..
In any way, just would like to hear the opinions of fellow EpiServer developers on this subject. Thank you
By the way, why Injected<T> is anti-pattern?