CodeDigest.Com Logo
Featured:

Using In-built Dependency Injection Framework in Asp.Net Core MVC

Tagged as: Asp.Net Core Asp.Net Core MVC Posted By

Dependency Injection is one of the most widely used pattern for creating loosely coupled application. For instance, a Controller class that has dependency on an external service should be built in such a way that the dependent service should be easily replaceable. In other words, the controller should not take care of dependent service instantiation and the implementation details of the dependent service should be encapsulated from the Controller class. The controller should operate only on the interface of the dependent service whose implementation or the concrete object should be injected to it during runtime. This is where Dependency Injection pattern is used.

Read the Quick Start article What is Dependency Injection? How to use this Pattern in Asp.Net MVC? to know more about this pattern.

The previous versions of Asp.Net MVC framework are designed to use dependency injection using some third party IOC containers like StructureMap, Autofac, NInject, etc. The Asp.Net Core framework includes its own implementation of a DI framework which is used by the MVC internally and also allows developers to use it for the application dependency without a need to integrate a third party component. The default implementation can also be replaced by a third party component if required.

Let’s move forward and understand how to use this inbuilt dependency injection framework in Asp.Net Core.

Using the In-built DI Container

When there is a dependency declared in a constructor, the inbuilt DI framework will automatically inject the concrete implementation object during instantiation. For example, consider the below PostController constructor which has a dependency declared on IPostRepository class.

 

public PostController(IPostRepository _repositoryPost)
{
    repositoryPost = _repositoryPost;
}
 

When MVC receives a request for an action method in PostController, it in turn requests a framework component called Service Provider to provide an instance of PostController object. The service provider will now take care of instantiating the PostController by injecting the implementation object of IPostRepository interface.

To enable the service provider to inject the dependent object, the interface to concrete class mapping has to be done in ConfigureServices(IServiceCollection services) method in Startup class. For IPostRepository, we have to map the concrete class PostRepository like below.

 

public void ConfigureServices(IServiceCollection services)
{
    //Removed for brevity
    services.AddTransient<IPostRepository, PostRepository>();
}


 

The method that is used to map the dependency (AddTransient()) is generally called service lifetime extensions. There are totally 3 overloaded service lifetime extensions defined in IServiceCollection class for adding dependencies. We will see more about these methods later in this article.

Resolving Chain of Dependencies

The inbuilt DI container also helps to resolve chain of dependencies declared for a service in Asp.Net Core applications. In the above example, let’s assume the concrete PostRepository class has already defined a dependency on DBModel object like below.

 

private DBModel dbContext;
public PostRepository(DBModel _dbContext)
{
    dbContext = _dbContext;
}
 

In this case, the service provider will resolve a chain of dependencies i.e. it first instantiate the PostRepository object by injecting its dependent object (DBModel) and then instantiates the PostController by injecting the PostRepository instance. Certainly, we need to register the DBModel object in Startup.ConfigureServices() method like below.

 

public void ConfigureServices(IServiceCollection services)
{
    //Removed for brevity

    services.AddDbContext<DBModel>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddTransient<IPostRepository, PostRepository>();
}
 

The AddDbContext() is an extension method in IServiceCollection specially added to register Entity Framework’s DbContext object. Like registering an interface to concrete object, the inbuilt container can also be used to add concrete object dependencies like above. In our example, the service provider will instantiate the concrete object (DBModel) and inject it into the constructors that declares DBModel as dependency.

Service Lifetime Extension Methods

As I said before, the Service Provider needs the dependent object type and its concrete implementation type to be registered in IServiceCollection for resolving the dependencies. This can be done from Startup.ConfigureServices() method as seen in above examples. The IServiceCollection exposes number of extension methods for registering the dependent object types based on the lifetime the objects are required in the application. In other words, the instantiated dependent objects life time depends on this registration methods it is used to register. There are basically 3 lifetime overloaded methods exposed in IServiceCollection class for registering dependencies. They are,

  1. Transient

When a dependency is registered using this method, the service provider will create a new instance of the concrete type each time it resolves a dependency. The overloaded methods for this lifetime are,

  1. AddTransient<TService>(Func<IServiceProvider, TService> implementationFactory)

This method takes a factory method which will be called by the service provider to instantiate the registered object every time a dependency is resolved.

  1. AddTransient<TService>()

This method takes a concrete implementation class which will be instantiated when there is a dependency defined for a concrete class similar to an interface as dependency.

  1. AddTransient(Type serviceType)

This method too adds a concrete implementation class which will be instantiated when there is a dependency defined for a concrete class similar to an interface as dependency.

  1. AddTransient<TService, TImplementation>()

This registers the interface to concrete class mapping. The mapped concrete class will be instantiated for the defined interface dependency. Our example code above.

  1. AddTransient<TService, TImplementation>(Func<IServiceProvider, TImplementation> implementationFactory)

Similar to 4th overload but the factory method is called to instantiate the dependent object.

Note - In short, each lifetime method will allow us to create a simple registration by just specifying the interface and concrete class or directly a concrete class or pass a factory method that will be called by service provider to instantiate the dependent object.

For brevity, I have only included description for Transient lifetime extensions. The other 2 extensions overloads listed are similar to these methods signature.

 

  1. Scoped

A new object per request is instantiated when registered using this method. There are multiple overload methods are available that works similar to transient methods for registering objects in this lifetime. The methods are,

AddScoped<TService>()

AddScoped(Type serviceType, Type implementationType)

AddScoped(Type serviceType, Func<IServiceProvider, object> implementationFactory)

AddScoped<TService, TImplementation>()

AddScoped(Type serviceType);

AddScoped<TService>(Func<IServiceProvider, TService> implementationFactory)

AddScoped<TService, TImplementation>(Func<IServiceProvider, TImplementation> implementationFactory)

 

  1. Singleton

The dependent object will be instantiated as singleton object i.e. an instance is created for the first time and it is reused for the application lifetime. The overloaded methods are,

AddSingleton<TService, TImplementation>(Func<IServiceProvider, TImplementation> implementationFactory)

AddSingleton<TService>(Func<IServiceProvider, TService> implementationFactory)

AddSingleton<TService>()

AddSingleton(Type serviceType)

AddSingleton<TService, TImplementation>()

AddSingleton(Type serviceType, Func<IServiceProvider, object> implementationFactory)

AddSingleton(Type serviceType, Type implementationType)

AddSingleton<TService>(TService implementationInstance)

AddSingleton(Type serviceType, object implementationInstance)

 

In next part, let’s see how to use this inbuilt DI framework to resolved dependencies in views, action methods and how to manually get an instance of a dependent object registered in the inbuilt container.

Happy Coding!!

Further Reading

  1. Read Difference Between Asp.Net and Asp.Net Core for a side by side difference.
  2. To know more about the new features in Asp.Net Core, read Breaking Changes and New Features of Asp.Net Core MVC.


Feedback

Comments