Dependency Injection in ASP.Net classes for TDD
In Asp.Net classes there is not built in library like Unity
or Autofac.
What’s the problem
with plain c# classes?
The reason for that is, in MVC or Web API Controller objects
are created via IHttpControllerActivator interface which is inherited by a
class. In Unity library IDependencyResolver is user which is kind of a
ServiceLocator anti-pattern hence objects of controllers are created without manual
intervention
This IHttpControllerActivator lies in API pipeline to
instantiate controllers
Now when we develop c# classes and code becomes too big and
complicated and automatically becomes tightly coupled which makes TDD harder
and next to impossible as once because there is no way to inject mock/test
classes instead of actual DB or dll library classes
How to solve it?
We can create a ServiceLocator anti-pattern in plain old
.net classes for DI purpose. Instead of directly creating object of third party
dll library we can simply register those in ServiceLocator anti-pattern and
then resolve the dependency within the scope of the anti-pattern
</>
public class ServiceLocator
{
// Key =
interface type
// Value
= concrete type that implements the Key interface
private static readonly Dictionary<Type,
ServiceTypeContainer> types;
// used
for locking, especially when creating objects using reflection
private static object syncObject = new object();
static ServiceLocator()
{
types = new Dictionary<Type,
ServiceTypeContainer>();
Register<IDependency>(typeof(Dependency));
}
public static T
Resolve<T>()
{
ServiceTypeContainer
typeContainer = types[typeof(T)];
T returnObj;
if (typeContainer.Initializer == null)
{
// CreateInstance uses a static cache that is not thread-safe
// We could change the lock to on typeContainer if this becomes a
bottleneck
lock (syncObject)
{
returnObj =
(T)Activator.CreateInstance(typeContainer.ServiceType);
}
}
else
{
returnObj =
(T)typeContainer.Initializer();
}
return returnObj;
}
public static void Register<T>(Type objT)
{
Register<T>(objT, null);
}
public static void Register<T>(Type objT, ServiceInitializer
initializer)
{
types.Add(typeof(T), new ServiceTypeContainer(objT, initializer));
}
}
public class ServiceTypeContainer
{
public Type ServiceType
{
get;
private set;
}
public ServiceInitializer Initializer
{
get;
private set;
}
public ServiceTypeContainer(Type serviceType, ServiceInitializer initializer)
{
ServiceType = serviceType;
Initializer = initializer;
}
}
public delegate object ServiceInitializer();
There are two classes
above one is used to register classes and another type container
Now instead of tightly
coupled code you can register all the third party dll classes in anti-pattern
and then use it like with the interface only
As you can see I have
registered the Dependency
class using IDependency
type and later I will resolve it using IDependency
only
Practicle
Below is a class ProductHistoryClass which has parameterized constructor
that takes a custom type as an argument which is in fact a reference to a
service or a dll class calling another method
public class ProductHistoryClass
{
private IDependency dependency;
public ProductHistoryClass(IDependency _dependency)
{
dependency = _dependency;
}
public int
FindProductHistory()
{
return dependency.FindProductHistory();
}
}
Below are our dependency Interface
and class
public interface IDependency
{
int FindProductHistory();
}
public class Dependency : IDependency
{
public Dependency()
{
}
public int
FindProductHistory()
{
return 1;
}
}
I have kept declaration
and definition simple to understand
Now in old ways we would
be creating object of Dependency class and then pass the object into constructor
calling of ProductHistoryClass which makes our classes tightly
coupled and difficult to modify in future
So how to make use of anti-pattern
here.
Don’t worry I got it covered J
In you calling class you can do like
public static void WithParam()
{
ProductHistoryClass prdCls =
(ProductHistoryClass)Activator.CreateInstance(classType,ServiceLocator.Resolve<IDependency>());
int res = prdCls.FindProductHistory();
}
Here I have used
reflection to create object or ProductHistoryClass and ServiceLocator to
resolve our dependency
And just by these simple
lines of code we are able to inject dependency in plain old c# classes
Now I would like you guys
to experiment with this.
This is it from this blog
hold tight till I write next one
J
If you like the blog then please like it and leave a
comment
Do not forget to subscribe.
Thank you.
No comments:
Post a Comment