If you are a seasoned Episerver developer, you should (and probably, already) know about the foundation of the framework: dependency injection. With the Inversion of control framework (most common, Structuremap, but recent versions of Framework allow much more flexible options), you can easily register your implementations, without having to manually create each and every instance by new
operator. Sounds great, right? Yes it is.
And Episerver Framework allows you to make it even easier by this nice ServiceConfiguration
attribute:
[ServiceConfiguration]
public class MyClass
{
}
so your class will be automatically registered, and whenever you need an instance of MyClass
, IoC framework will get the best instance for you, automatically, without breaking a sweat. Isn’t it nice? Yes it is.
But I guess you also saw this from place to place
[ServiceConfiguration(LifeCycle = ServiceInstanceScope.Singleton)]
public class MyClass
{
}
So instead of creating a new instance every time you ask it to, IoC framework only creates the instance once and reuses it every time. You must think to yourself: even nicer, that would save you a lot of time and memory.
But is it (nicer)?
You might want to think again.
Singleton means one thing: shared state (or even worse, Global state). When a class is marked with Singleton, the instance of that class is supposed to be shared across the site. The upside, is, well, if your constructor is expensive to create, you can avoid just that. The downside, of course, shared state can be a real b*tch and it might come back to bite you. What if MyClass
holds the customer address of current user. If I set my address to that, and because you get the same instance, you’ll gonna see mine. In Sweden it’s not a real problem as you can easily know where I live (even my birthday if you want to send a gift, or flowers), but I guess in the bigger parts of the world that is a serious privacy problem. And what if it’s not just address?
And it’s not just that, Singleton
also make things complicated with “inherited singleton”. Let’s take a look at previous example. Now we see Singleton
is bad, so let’s remove that on our class. But what if other class depends on our little MyClass
:
[ServiceConfiguration(LifeCycle = ServiceInstanceScope.Singleton)]
public class MyOtherClass
{
private MyClass _myClass;
public MyOtherClass(MyClass myClass)
{
_myClass = myClass;
}
}
Now I hope you see where the problem is. One instance of MyOtherClass
is shared inside the side. And it comes with an attached MyClass
instance. Even if you don’t intend to, that MyClass
instance will also be shared. Same problem after all.
Singleton
was there to solve one problem (or two), but it can also introduce other problems if you don’t really think about if your instance should be shared or not. And not just your class, the classes which have dependency on your class as well.
And it’s not just Singleton
, HttpContext
and Hybrid
might also subject to same problem, but to a lesser extend. Any lifecycle that shares state should be considered: if you really need it and what you are sharing.
Lifecycle is hard, but it can also work wonder, so please take your time to make it right. It’s worth it.