Introduction
This blog explains how to manage tightly coupled C# classes and make them loosely coupled. In ASP.NET classes, there is not a built-in library like Unity or Autofac.
What’s the problem with plain C# classes?
The reason for that is that in MVC or Web API Controller, objects are created via IHttpControllerActivator interface, which is inherited by a class. In Unity library IDependencyResolver is the user, which is kind of a ServiceLocator anti-pattern. Therefore, objects of controllers are created without manual intervention
This IHttpControllerActivator lies in the API pipeline to instantiate controllers.
Now when we develop C# classes and the code becomes too big and complicated, it automatically becomes tightly coupled, which makes TDD harder and next to impossible because there is no way to inject mock/test classes instead of the 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.
- namespace DIviaReflection
- {
- public class ServiceLocator
- {
- // Key = interface
- // 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();
- }

Rikam PalkarPosted Apr 17, 2020, 6:46 AM
Good job, I liked the example.
graeme thomsonPosted Apr 16, 2020, 9:19 PM
Thankyou. I am trying to get my head around DI and EF and Blazor. I am finding it a challenge but articles such as yours are a huge help. I will need to read it at lease 5 times before I understand what you are describing, but I will get there!!!!