About Microsoft Extension: DependencyInjection has introduced a lot, but most of the emphasis on the realization of the principles and some specific implementation scenario. As the cornerstone dotnet core of the core, where it prepared a comprehensive presentation of concepts, principles and use.
Here first introduced the concept of parts.
1. Concept
The project's GitHub address: https://github.com/aspnet/Extensions/tree/master/src/DependencyInjection
Microsoft.Extensions.DependencyInjection
It is Microsoft's implementation of the Dependency Inversion principle. As the cornerstone of ASP.NET Core, DependencyInjection
throughout all aspects of the project, to master its use and principles, not only is important for understanding ASP.NET Core, also it helps to apply it to the development of other projects to help provide project the development efficiency and quality.
Scene 1.1 problem
In software development, projects often have a number of different modules, dependencies between modules. For example, we consider a simplified scenario, we have three categories of user:
-
AccountController, provide a user interface
-
UserService, provides the business logic user management
-
UserRepository, to provide data access to user management
AccountController
Internal need UserService
instance to manage user, while UserService
the inside is based on the need UserRepository
to provide data access. We call dependencies between them. Alternatively expressed, AccountController
dependent on UserService
, and UserService
rely on UserRepository
. The dependency injection is a powerful tool to help us achieve our dependency management.
1.2 Dependency Inversion Principle DIP
Dependency Inversion principle is one of the well-known design principles, the principle is the theoretical cornerstone of software projects decoupling module.
Defined principles are as follows:
High level modules should not depend upon low level modules,Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstracts.
Translated as:
-
High-level modules should not depend on low-level modules, both of which should rely on abstract
-
Abstract should not rely on the details
-
Details should depend abstract
In the absence of realization of the principle of dependency inversion, we passed in AccountController
class by themselves new
to create its dependence on key UserService
object instance,
public class AccountController { private readonly UserService _userService; public AccountController() { this._userService = new UserService(); } }
This has led to tight coupling between the two classes, AccountController
and UserService
is bound together to create each AccountController
time, will create an UserService
object instance, and if we need to test AccountController
time, will have to consider UserService
such a dependent class level down, UserService
will depend on UserRepository
, you will find classes in your project are bound together tightly coupled, difficult to split.
Based on the principle of dependency inversion usually consider isolation through the interface. For example, we might define a user interface to services:
public interface IUserService { }
The customer service will implement the interface
public class UserService : IUserService { }
In AccountController
class, the change became based interface to use UserService
.
public class AccountController { private readonly IUserService _userService; public AccountController() { this._userService = new UserService(); } }
While HomeController
inside, we can interface-based programming, but this approach does not solve by yourself new
to get the UserService
problem object instance.
1.3 Inversion of Control IoC
IoC
DIP is a well-known design patterns to achieve.
Its core idea is: when needed object instance, do not always consider themselves through new
to create the object, put down the process of creating dependent objects, but to create an object to be responsible for the work to someone else, the people we usually called container ( Container) or service provider (ServiceProvider) , we use this later ServiceProvider
to refer to it,
From this object instance when needed ServiceProvider
get in.
The following is a schematic diagram of a widely used. Take always bring, but from their own wear becomes for you to wear
The inversion of control, the introduction of a ServiceProvider to help us get object instance .
1.4 Dependency injection DI (DependencyInjection)
DI is an implementation of IoC pattern.
《Expert one on one J2EE Development without EJB》第 6 章
Main way to achieve IoC in two ways: dependent lookup, dependency injection (p128)
Dependency injection is a more desirable way. (P130)
Martin Fowler's original text:
As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.
To the effect that:
Already exists a certain mode, which is called IoC, but IoC too broadly, any IoC frameworks, in order to allow ideographic more clearly, decided to use DI to precise allegations it.
There are multiple implementations of the DI, we presented here is DependencyInjection Microsoft official in the Microsoft Extension built to offer. It is IoC in an implementation, the entire core ASP.NET Core-based to achieve it. At the same time, we can also be used in other projects, in order to achieve support for the Dependency Inversion principle.
2. DependencyInjection basic concepts of
2.1 Service Description collection ServiceCollection
Microsoft's DI implementation, all services need to be registered to a common description of the collection service, the DI for the entire collection, the only one, serving only need to register once in this collection, you can later by DI provided to the user.
Interface defines the collection as can be seen, it is actually used to save a set of services registered.IServiceCollection
public interface IServiceCollection : IList<ServiceDescriptor>, ICollection<ServiceDescriptor>, IEnumerable<ServiceDescriptor>, IEnumerable { }
The default has achieved one pair IServiceCollection
of realization called . In ASP.NET Core, the interior creates an instance of the object, we can also in other projects, to create its own, very simple, straight out ready for use.ServiceCollection
new
IServiceCollection services = new ServiceCollection ();
2.2 Service Service
In DI context, especially by the service object instance DI container management. This service does not have to be called ** Service, but can be any object managed by the DI, DI is only in this context, we will be collectively referred to as service.
Service is our own definition, such as the previously mentioned AccountController
and UserService
so on.
We get to serve instance, life cycle management service object through DI, for complex objects exist dependencies, DI also manages dependencies between these instances.
Services must first register in order to use the DI, however, pre-registration and decisions need to consider the life cycle of services.
2.3 Life Cycle Service
Service object instance has a different type of life cycle. Some of the life cycle of an object with the same application, created when the application starts, to be released only when the application exits. For example, our data access object instance. Some objects only used in the current method, after the end of the method call should be destroyed. Lifecycle management services used to manage these needs.
DI supports three types of life cycle:
-
Singleton, singleton, only one instance in the current application environment. Services such as data access object instance.
-
Scoped, limited range, once out of this range, in this range of service objects need to be destroyed. For example, Web development request object instance.
-
Transient, transient, one-time use, each obtained from the DI, return a new instance.
Microsoft.Extensions.DependencyInjection.ServiceLifetime
public enum ServiceLifetime { Singleton, Scoped, Transient }
Lifecycle Services is determined at the time of registration services. When in use, direct access to instance, no longer designated lifecycle services. Microsoft offers a variety of ways to facilitate the expansion of services specified in the registration service lifecycle. Here, for example, the life cycle is specified by the single generic way of embodiment modes.
// based interface register services.AddSingleton <IUserService, UserService> () ;
2.4 Service Provider ServiceProvider
Not get to use the service when needed from the set of object instances registration service, but need to get through the service provider, the service provider is a clear need from the set of registered services. Service provider interface defined , it is one of the basic definition of .net, not defined in the DI framework.IServiceProvider
public interface IServiceProvider { object GetService(Type serviceType); }
The DI expanded to provide support for the service provider to obtain the ServiceProvider.ServiceCollectionContainerBuilderExtensions
IServiceCollection
public static ServiceProvider BuildServiceProvider(this IServiceCollection services) { return BuildServiceProvider(services, ServiceProviderOptions.Default); }
So, we usually use this method to obtain and use it.
// create a registration service container IServiceCollection Services = new new ServiceCollection (); // registration service, here designated single embodiment services.AddSingleton <IUserService, UserService> (); // get the service provider through the vessel IServiceProvider provider = services.BuildServiceProvider ();
2.5 object instance access to services
By the service provider to obtain service manual object instance. By type of service registration, direct call GetService
method can be.
For example, in front of us signed up for the type of service IUserService
implementation type is UserService
, you can get to the actual instance of the object that implements this interface by means of this type.
// create a registration service container IServiceCollection Services = new new ServiceCollection (); // registration service, here designated single embodiment services.AddSingleton <IUserService, UserService> (); // get the service provider through the vessel the IServiceProvider Provider = services.BuildServiceProvider (); // Get the service object through the interface instance IUserService instance = provider.GetService <IUserService> ( );
It seems more complicated. In actual use, we rarely use such a way to use DI, later we go any further specific use.