Dependency Injection Before ASP.NET Core
Hamida Rebai Trabelsi
Cloud Solutions Architect| Docker Captain |Microsoft Certified Trainer|2X Packt Book Author|LinkedIn Learning Institutor| Public Speaker |Mentor| Digital Transformation Enthusiast| FinOps, Cloud Strategy & AI Integration
What is Dependency Injection?
Wikipedia says: "Dependency injection is a software design pattern in which one or more dependencies (or services) are injected, or passed by reference, into a dependent object (or client) and are made part of the client's state. The pattern separates the creation of a client's dependencies from its own behavior, which allows program designs to be loosely coupled and to follow the dependency inversion and single responsibility principles. It directly contrasts the service locator pattern, which allows clients to know about the system they use to find dependencies.".
So, from Wikipedia definition, we resume that Dependency Injection (DI) is a technique used to loose coupling between objects or dependencies.It is a sub-approach forming part of the global concepts of inversion of control. Its principle is such that a subroutine must express the dependencies it needs to function. The IoC container is then used to instantiate the subroutine; Taking into account these dependencies. The injection of dependencies can take several forms: via a constructor, via a
property, via a private field, and so on. This depends on the library used and the conceptual choices used in the project.
This technique is used always when we would like to manage dependencies and to develop a modular and well-structured application.
Dependency Injection in MVC
It is possible to easily transpose the principle of injection of dependencies in the following way. The controller here expresses its dependencies via its constructor.
public class DIController : Controller
{
private readonly IDependencyInjectionService _dependencyInjectionService;
public MyController(IDependencyInjectionService dependencyInjectionService)
{
_dependencyInjectionService = dependencyInjectionService;
}
}
//And in the main class
static void Main(string[] args)
{
var unityContainer = new UnityContainer();
unityContainer.RegisterType<IDependencyInjectionService , DependencyInjectionService>();
var instance = unityContainer.Resolve<DIController>();}
Before ASP.NET Core
The previous example is a bit special. Indeed, if you run it as is, at runtime, the program does not work.
Indeed, the default behavior of the controller factory is to expect that the default constructor (without arguments) is present on the controllers to be instantiated. The factory uses the Activator class of the.NET Framework and its CreateInstance method.
With ASP.NET MVC 4 and 5, the solution usually consists of replacing the dependency resolution mechanism of the library (the DependencyResolver class) with an implementation connected to the IoC container.
With ASP.NET Web API 1 and 2, it is also necessary to replace a service in the library with an implementation plugged into the IoC container. However, the differences in internal operation between the two libraries mean that the service to be replaced is not exactly the same.
Using a library such as Unity, it is possible to retrieve a NuGet package adapted to ASP.NET MVC which automatically downloads the Bootstrapper class below. Notice the call to the SetResolver method of the DependencyResolver class. It is this call that makes it possible to replace the mechanism of resolution and instantiation of the services for all the ASP.NET MVC part of an application. Let's start with an example:
public static class UnityConfig
{
public static IUnityContainer Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
}
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IDependencyInjectionService , DependencyInjectionService>();
}
}
The instance passed to SetResolver must simply implement an IDependencyResolver interface, which is present in the System.Web.Mvc namespace.
public interface IDependencyResolver
{
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}
ref : https://msdn.microsoft.com/en-us/library/system.web.mvc.idependencyresolver(v=vs.118).aspx
And it is at this level that the simple implementation by default and using the Activator class is defined. It is this class that we replace when we use the SetResolver method.
private class DefaultDependencyResolver : IDependencyResolver
{
public object GetService(Type serviceType)
{
if (serviceType.IsInterface || serviceType.IsAbstract)
{
return null;
}
try
{
return Activator.CreateInstance(serviceType);
}
catch
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return Enumerable.Empty<object>();
}
}
With ASP.NET Web API 2, implementation requires the creation of a class that meets the IDependencyResolver contract. The name space of the latter is System.Web.Http.Dependencies.
public interface IDependencyResolver : IDependencyScope, IDisposable
{
IDependencyScope BeginScope();
}
public interface IDependencyScope : IDisposable
{
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}
The instantiation and definition of the Resolver so that it can be used with the Web API controllers is ultimately done in a totally different way.
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<IDependencyInjectionService, DependencyInjectionService>();
config.DependencyResolver = new UnityResolver(unityContainer);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Note that both technologies, ASP.NET MVC and ASP.NET Web API have the basics to enable injection of dependencies. The DependencyResolver mechanism is present as a base. However, by default, it is not plugged into an IoC container. In addition, each technology uses its own mechanism. For an application that mixes MVC and Web API controllers, it is, therefore, necessary to create two DependencyResolver homes and plug them into the same IoC container.
Note that SignalR, another ASP.NET brick also has its own mechanism, also different from those presented above.
Blog link :https://hamidarebai.blogspot.it/2017/07/dependency-injection-in-aspnet-core-di.html
See Source Code in GitHub:
https://github.com/didourebai/DIProject