"ASP. NET Core" ASP-Dependency Injection

Source: Internet
Author: User
Tags httpcontext

I. What is dependency injection (denpendency injection) This is also a laoshen talk about question, in the end what is dependency injection? Why do you use it? It is particularly easy for beginners to be dizzy with the concept of control reversal IOC (iversion of controls) and Di. 1.1 Dependencedependency occurs when a class needs to collaborate on another class to do its job . For example, we are accountcontroller this controller needs to complete and user-related registration, login and other things. The login is done by EF with idnetity, so we encapsulate a efloginservice. Here AccountController there is a iloginservice of dependency . Here's a design principle: rely on abstraction, not concrete implementations. So we define an interface for Efloginservice, which abstracts the behavior of Loginservice. 1.2 What is injectedInjection embodies an IOC (the idea of inversion of control). Before we flip, let's look at the positive turn. AccountController yourself to instantiate the needs of dependency .
12345 privateILoginService<ApplicationUser> _loginService;public AccountController(){  _loginService = newEFLoginService()} 

The master said it was not good. You should not create it yourself, but should be given to you by your caller. So you use the constructor to let the outside world pass these two dependencies on to you.

12345 public AccountController(ILoginService<ApplicationUser> loginService){  _loginService = loginService;}

Throw the creation of dependencies to others, use them only, and the process that others throw at you is understood as injection.

1.3 Why reverse?to minimize the potential for changes in the code when the business is changing. For example, we are now going to change from EF to verify login to read from Redis, so we added a redisloginservice. At this point we just need to change it in the place where it was originally injected.
var controller = new AccountController (new Efloginservice ()); controller. Login (userName, password);//use Redis to replace the original EF login var controller = new AccountController (new Redisloginservice ()); Controller. Login (userName, password);
1.4 What is a containerwhen we were using AccountController, we created an instance of Iloggingservce ourselves through the code. Imagine if there were 100 such places in a system, would we be doing something like this in 100 places? Control is reversed, and dependency creation is handed over to the outside. The problem now is that we need a place where all the dependencies of a unified management system, the container is born. The container is responsible for two things:
    • The relationship between a bound service and an instance
    • Get instances and manage instances (create and destroy)
Ii. registration of. NET Core DI 2.1 instancesafter the key concepts of Di and IOC are clear, let's take a look at the application of. NET Core di in the console. The core of Di in. NET core is divided into two components: Iservicecollection and IServiceProvider.
    • Iservicecollection is responsible for registering
    • IServiceProvider is responsible for providing examples
There are three methods through the default Servicecollection (under the Microsoft.Extensions.DependencyInjection namespace):
  var servicecollection = new Servicecollection ()  . Addtransient<iloginservice, efloginservice> ()  . Addsingleton<iloginservice, efloginservice> ()  . Addscoped<iloginservice, efloginservice> ();
all three of these methods register our instances, except that the life cycle of the instances is different. When is the life cycle going on in our next section? the default implementation of Servicecollection is to provide a list of Servicedescriptor
public Interface iservicecollection:ilist<servicedescriptor>{}

The AddTransient, Addsignletone, and scoped methods above are the iservicecollection extension methods, all of which add servicedescriptor to the list.

private static Iservicecollection Add (  iservicecollection collection,  type servicetype,  type Implementationtype,  servicelifetime lifetime) {  var descriptor =   New Servicedescriptor (ServiceType, Implementationtype, lifetime);  Collection. ADD (descriptor);  return collection;}
2.2 Example life cycle of a single instanceas we saw above, the. NET Core DI provides us with the instance Life Week which includes three kinds:
    • Transient: Each time a getservice creates a new instance
    • Scoped: Only one instance is initialized within the same scope, which can be understood as (only one instance is created per request level, and the same HTTP request is within a scope)
    • Singleton: Create only one instance within the entire application life cycle
three enumerated values corresponding to Microsoft.Extensions.DependencyInjection.ServiceLifetime
public enum servicelifetime{  Singleton,  Scoped,  Transient}
for everyone to better understand the concept of this life cycle, we do a test:defining a basic ioperation has a OperationID attribute, and Ioperationsingleton is just another interface.
public interface ioperation{        Guid operationid {get;}} Public interface Ioperationsingleton:ioperation {}public Interface Ioperationtransient:ioperation{}public interface I operationscoped:ioperation{}

Our operation implementation is simple, you can pass in the constructor a GUID to assign the value, if not, then the new GUID.

public class Operation:   Ioperationsingleton,  ioperationtransient,  ioperationscoped{    Private Guid _ GUID;    Public operation () {        _guid = Guid.NewGuid ();    }    Public operation (GUID guid)    {        _guid = GUID;    }    Public Guid OperationID = _guid;}

Within the program we can call ServiceProvider's GetService method multiple times and get to the same instance.

var services = new Servicecollection ();//default construction services. Addsingleton<ioperationsingleton, operation> ();//Custom incoming GUID null value Services.addsingleton<ioperationsingleton > (  new Operation (Guid.Empty));//Custom pass in a new Guidservices.addsingleton <IOperationSingleton> (  new Operation (Guid.NewGuid ())); var Provider = Services. Buildserviceprovider ();//Output singletone1 Guidvar singletone1 = provider. Getservice<ioperationsingleton> (); Console.WriteLine ($ "signletone1: {singletone1. OperationID} ");//Output singletone2 Guidvar Singletone2 = provider. Getservice<ioperationsingleton> (); Console.WriteLine ($ "signletone2: {singletone2. OperationID} "); Console.WriteLine ($ "singletone1 = = Singletone2?: {singletone1 = = Singletone2}");

We registered to Ioperationsingleton three times, and finally get two times, we have to notice that we have always been the last time we registered the one that gave a GUID instance, the front will be overwritten.

Tranisent of 2.3 Instance life cycle

This time we get the ioperationtransient for two different instances.

var services = new Servicecollection (); services. Addtransient<ioperationtransient, operation> ();    var Provider = Services. Buildserviceprovider (); var transient1 = provider. Getservice<ioperationtransient> (); Console.WriteLine ($ "transient1: {transient1. OperationID} "); var Transient2 = provider. Getservice<ioperationtransient> (); Console.WriteLine ($ "Transient2: {transient2. OperationID} "); Console.WriteLine ($ "transient1 = = Transient2?:   {transient1 = = Transient2}");
Scoped of 2.4 instance life cycle. NET Core Human IServiceProvider provides createscope to produce a new serviceprovider scope, in which instances of scope annotations will only be the same instance. In other words: the object registered with scope is equivalent to a single case under the scope of the same serviceprovider. We also first register ioperationscoped, ioperationtransient and Ioperationsingletone three instances, with corresponding scoped, Transient, and Singleton life cycle.
var services = new Servicecollection (). addscoped<ioperationscoped, Operation> (). Addtransient<ioperationtransient, Operation> (). Addsingleton<ioperationsingleton, operation> ();

Next we use the Serviceprovider.createscope method to create a scope

var Provider = Services. Buildserviceprovider (); using (var scope1 = provider. Createscope ()) {    var p = scope1. serviceprovider;    var scopeobj1 = p.getservice<ioperationscoped> ();    var transient1 = p.getservice<ioperationtransient> ();    var singleton1 = p.getservice<ioperationsingleton> ();    var scopeobj2 = p.getservice<ioperationscoped> ();    var transient2 = p.getservice<ioperationtransient> ();    var singleton2 = p.getservice<ioperationsingleton> ();    Console.WriteLine (        $ "scope1: {scopeobj1. OperationID}, "+        $" transient1: {transient1. OperationID}, "+        $" Singleton1: {singleton1. OperationID} ");    Console.WriteLine ($ "scope2: {scopeobj2. OperationID}, "+        $" Transient2: {transient2. OperationID}, "+        $" Singleton2: {singleton2. OperationID} ");}

Next

scope1:200d1e63-d024-4cd3-88c9-35fdf5c00956, transient1:fb35f570-713e-43fc-854c-972eed2fae52, singleton1: Da6cf60f-670a-4a86-8fd6-01b635f74225scope2: 200d1e63-d024-4cd3-88c9-35fdf5c00956, transient2: 2766a1ee-766f-4116-8a48 -3e569de54259, singleton2:da6cf60f -670a-4a86-8fd6 -01b635f74225            

If you create a new scope operation again,

scope1: 29f127a7-baf5-4ab0-b264-fcced11d0729, transient1: 035d8bfc-c516-44a7-94a5-3720bd39ce57, singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225scope2: 29f127a7-baf5-4ab0-b264-fcced11d0729, transient2: 74c37151-6497-4223-b558-a4ffc1897d57, singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225
It is noted that we have 4 transient instances, 2 scope instances, and 1 singleton instances in total.What's the use of this? if the AUTOFAC instanceperrequest in MVC knows that there are objects in a request that spans multiple actions or multiple service, repository, For example, the most commonly used dbcontext it can be an instance. It can reduce the consumption of instance initialization, and also can realize the function of cross service transaction. (Note: All service with EF is required to be registered as scoped in ASP.)The way to achieve this is to share a scope within the lifetime of the entire reqeust request. Iii. application of Di in ASP. 3.1 Initialize in startup classASP. NET core can be configured in the Startup.cs configureservice di, you see iservicecollection This parameter should be more familiar with.
public void Configureservices (iservicecollection services) {    services. Addtransient<iloginservice<applicationuser>,       efloginservice> ();    Services. ADDMVC ();)

Some of the components of ASP. NET core already provide some instance bindings, like Addmvc is the extension method that MVC middleware adds on iservicecollection.

public static Imvcbuilder Addmvc (this iservicecollection services) {    if (services = = null)    {        throw new ArgumentNullException (nameof (services));    }    var builder = Services. Addmvccore ();    Builder. Addapiexplorer ();    Builder. Addauthorization ();    Adddefaultframeworkparts (builder. Partmanager);    ...}
Used in 3.2 controllerinjections can generally be implemented by constructors or properties, but the official recommendation is through constructors. This is also known as the explicit dependency .
Private iloginservice<applicationuser> _loginservice;public AccountController (  iloginservice< Applicationuser> loginservice) {  _loginservice = Loginservice;}

As long as we write this parameter in the controller's constructor, ServiceProvider will inject us in. This is done at the time the MVC initializes the controller, and we'll talk about it in detail when we go back to MVC.

Use in 3.3 viewin view you need to use @inject and then declare, an alias.
@using milkstone.services; @model milkstone.models.accountviewmodel.loginviewmodel@inject iloginservice< Applicationuser>  loginservice<! DOCTYPE html>
3.4 Using HttpContext to get an instanceHttpContext a requestedservice can also be used to get instance objects, but this method is generally not recommended. Also note that getservice<> is a paradigm-by-default method, and it is not necessary to call this method if the using of Microsoft.Extension.DependencyInjection is not added.
Httpcontext.requestservices.getservice<iloginservice<applicationuser>> ();
Iv. How to replace the other IOC containersAUTOFAC is also a good choice, but first we need to figure out why we have to replace the default Di container? , what is the impact of the replacement? The default implementation for. NET core is fully sufficient for some small projects, even for large projects, but it can be cumbersome because it provides only the most basic addxxxx method to bind instance relationships, requiring one addition. If the project is likely to add a good hundreds of rows such a method. If you are familiar with AUTOFAC, you may have an image of this code below.
Builder. Registergeneric (typeof (Loggingbehavior<,>)). As (typeof (Ipipelinebehavior<,>)); Builder. Registergeneric (typeof (Validatorbehavior<,>)). As (typeof (Ipipelinebehavior<,>));

This will bring some convenience to our initialization, so let's look at how to replace AUTOFAC to ASP. We just need to change the return value of the Configureservice inside the startup class from void to IServiceProvider. And the return is a autoserviceprovider.

Public IServiceProvider configureservices (  iservicecollection services) {    services. Addmvc ();    Add other framework Services    //Add Autofac    var containerbuilder = new Containerbuilder ();    Containerbuilder.registermodule<defaultmodule> ();    Containerbuilder.populate (services);    var container = Containerbuilder.build ();    return new Autofacserviceprovider (container);}
4.1 What's changedOne of the big changes is that AUTOFAC's original life cycle Instanceperrequest, will no longer be effective. As we said earlier, the entire request lifecycle is managed by the ASP. NET core, so this AUTOFAC will no longer work. We can use Instanceperlifetimescope, which is also useful, corresponding to the scoped in our ASP. NET Core DI.

"ASP. NET Core" ASP-Dependency Injection

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.