To learn ASP., you must understand the ubiquitous "dependency injection"

Source: Internet
Author: User
Tags webhost

The core of the ASP is a pipeline consisting of a server and several registered middleware, whether the pipeline itself is built, or the server and middleware itself, and the application that is built into the pipeline, requires the support of the corresponding service, The ASP. NET core itself provides a DI container for registering and consuming services. In other words, not only is the service used by the ASP. NET Core framework to be registered and provided by this DI container, but the registration and delivery of application-level services is also required for this DI container, so as the title of this article says-learning ASP. You must understand the ubiquitous "dependency injection ”。

Directory one, Dependency injection introduction
Ii. application of Dependency injection in pipeline construction process
III. registration and injection of dependent services
Four, let startup's Configureservices method return a serviceprovider
Five, which services are registered by ASP.
Vi. dependency Injection in ASP. NET Core MVC

I. Introduction to Dependency Injection

When it comes to dependency injection (Dependency injection, hereinafter referred to as DI), it must be said that the IOC (inverse of Control), many people confuse these two, in fact, this is two completely different concepts, or different "levels" of two concepts, I have in the The two concepts are described in detail in control inversion (IoC) and Dependency Injection (DI). The DI framework used by the ASP. NET core is hosted by the "Micorosoft.Extensions.DependencyInjection" NuGet package, and we can use it separately from the ASP. NET core application or your own framework. For the design, implementation, and programming of this DI framework, I have described this in detail in the series "Dependency injection [Total 7]" in the article "ASP."

The DI framework has two core functions, namely the registration and delivery of services, which are hosted by corresponding objects, respectively, Servicecollection and serviceprovider. As shown, we register the corresponding service with different life cycle patterns (Transient, scoped, and Singleton) on top of the Servicecollection object, The serviceprovider created with the latter extracts the corresponding service objects based on the registered service type.

second, the use of dependency injection in the pipeline construction process

In the framework of the ASP. NET core pipeline, there are mainly three objects/types, as the host's webhost and his creator Webhostbuilder, and the startup type registered to Webhostbuilder. The following code snippet shows the typical programming pattern used by the launch of the ASP: we first create a Webhostbuilder object and register it with the server and startup type. Before calling the build method to create webhost, we can also call the appropriate way to do the other required registration work. When we call Webhost's Run method, the latter uses the registered startup type to build the complete pipeline. So how is di being used in the pipeline construction process?

   1:new Webhostbuilder ()
   2:     . Usekestrel ()
   3:     . Usestartup<startup> ()
   4:     . Xxx
   5:     . Build ()
   6:     . Run ()

The application of Di in the construction of the pipeline ASP. NET core pipeline is basically reflected in the following sequence diagram. When we call Webhostbuilder's build method to create the corresponding webhost, the former creates a Servicecollection object and registers a series of predefined services on it. Next Webhostbuilder will use this Servicecollection object to create the corresponding Servieprovider, The serviceprovider and Servicecollection objects are passed along to the final creation of the Webhost object. When we call Webhost's Run method to start it, if the registered startup is an instance type, it will use this serviceprovider to create the corresponding startup object in a constructor-injected manner. To be specific, the constructor of our registered startup type is allowed to define parameters, but the parameter type must be a service type that is pre-registered in Servicecollection.

The registered Startup method can contain an optional Configureservices method that has a parameter of type Iservicecollection interface. Webhost will call this configureservices method as a parameter by passing the Webhostbuilder to its servicecollection, We use this method to register the middleware and the services required by the application to this Servicecollection object. After that, all required services (including frameworks and application-registered services) are registered with this servicecollection, and webhost will use it to create a new serviceprovider. Webhost uses this ServiceProvider object to invoke the Configure method of the Startup object/type in a method-injected manner, and finally completes your build of the entire pipeline. In other words, the Configure method defined in the startup type that is intended to be used to register middleware can still use any of the service types registered as the type of subsequent arguments in addition to using Iapplicationbuilder as the first parameter.

The registration of a service, in addition to the Configureservices method of the now registered startup type, actually has another implementation, which is to call Webhostbuilder with the Configureservices method defined below. When Webhostbuilder creates the Servicecollection object and completes the registration of the default service, we call all the action<iservicecollection> passed in by this method The object will eventually be applied to the Servicecollection object.

   1:public Interface Iwebhostbuilder
   2: {
   3:     iwebhostbuilder configureserviecs (action<iservicecollection> configureservices);
   4:}

It is worth mentioning that the Configureservices method of the startup type is allowed to have a return value of type IServiceProvider, if this method returns a specific Serviceprorivder, Then webhost will not use Servicecollection to create the serviceprovider, but instead directly use the returned serviceprovider to invoke the Startup object/type Configure method. This is actually a very useful extension point, and we use it to implement integration for other DI frameworks.

III. registration and injection of dependent services

Next we demonstrate how to use the Startup type's configureservices to register the service and the two dependency injection forms that occur on the startup type. As shown in the following code snippet, we define two service interfaces (IFoo and Ibar) and the corresponding implementation types (foo and bar). Where the service foo is registered by calling Webhostbuilder's Configureservices method, and another service bar registration occurs on the startup Configureservices method. For startup, it has a read-only property of type IFoo, which is initialized with the arguments passed in by the constructor, needless to say that this represents the constructor injection for startup. The Configure method of startup, in addition to Applicationbuilder as the first parameter, also has another parameter of type Ibar, which we use to demonstrate method injection.

   1:public interface IFoo {}
   2:public interface IBar {}
   3:public class Foo:ifoo {}
   4:public class Bar:ibar {}
   
   6:public class Program
   7: {
   8: Public     static void Main (string[] args)
   9:     {
  Ten:         new Webhostbuilder ()
  One:             . Configureservices (services=>services. Addsingleton<ifoo, Foo> ())
  A:             . Usekestrel ()
  :             . Usestartup<startup> ()
  :             . Build ()
  :             . Run ();
  :     }
  17:}
  18:public class Startup
  19: {
  : Public     IFoo Foo {get; private set;}
  : Public     Startup (IFoo foo)
  :     {
  : This         . foo = foo;
  :     }    
  : Public     void Configureservices (iservicecollection services)
  :     {
  :         Services. Addtransient<ibar, bar> ();
  :     }
  29:     
  : Public     void Configure (Iapplicationbuilder app, IBar Bar)
  :     {
  +:         app. Run (Async context =
  :         {
  :             context. Response.ContentType = "text/html";
  A:             await the context. Response.writeasync ($ "ifoo=>{this. Foo}<br/> ");
  A:             await the context. Response.writeasync ($ "ibar=>{bar}");
  Panax Notoginseng:         });
  :     }
  39:}

In the Configure method of startup, we call Applicationbulder's Run method to register a middleware, which takes the type of two injected service as the content of the response. When we run this app and use the browser to access the default listening address (http://localhost:5000), the browser will show the type of two service objects injected.

Four, let startup's Configureservices method return a serviceprovider

We say that the configureservices of the registered startup type allows the return of a serviceprovider, which is important in that it enables us to implement with a third-party DI framework such as unity, Castle, Ninject and AUTOFAC, etc.) are integrated. We routinely use an example to demonstrate this, and for the sake of simplicity, we don't really use a specific DI framework to create this serviceprovider, but instead create a new servicecollection to create it directly, For this reason, we have rewritten the above program as follows.

   1:public class Program
   2: {
   3: Public     static void Main (string[] args)
   4:     {
   5:         New Webhostbuilder ()
   6:             . Usekestrel ()
   7:             . Usestartup<startup> ()
   8:             . Build ()
   9:             . Run ();
  Ten:     }
  11:}
  12:public class Startup
  13: {   
  : Public     IServiceProvider configureservices (iservicecollection services)
  :     {
  :         iservicecollection newservices = new Servicecollection ();
  +:         foreach (servicedescriptor service in services)
  :         {
  :             newservices.add (service);
  :         }
  
  :         return Newservices
  At:             . Addsingleton<ifoo, Foo> ()
  A:             . Addsingleton<ibar, Bar> ()
  :             . Buildserviceprovider ();
  :     }
  27:     
  : Public     void Configure (Iapplicationbuilder app, IFoo foo, IBar bar)
  :     {
  :         app. Run (Async context =
  :         {
  A:             context. Response.ContentType = "text/html";
  :             await the context. Response.writeasync ($ "ifoo=>{foo}<br/>");
  :             await the context. Response.writeasync ($ "ibar=>{bar}");
  :         });
  :     }
  37:}

As shown in the code snippet above, in the Configureservices method of startup, We generated a new servicecollection by copying all servicedescriptor registered to the existing servicecollection, and two service Foo and bar were registered to the latter. The method eventually returns the serviceprovider created by the new servicecollection. In another configure method, we added two parameters of type IFoo and Ibar, and in the same way their true type name and the mapping of the registration service type were used as response content. Once the program is running, we will get the same result when we access it using the browser.

Five, which services are registered by ASP.

Webhostbuilder after the servicecollection is created, some default services are registered. There is no difference between these services and our self-registered services, as long as we know the corresponding service types, we can obtain and use them in an injected manner. So what services are registered by default? As shown below are the types of these services, and as to what these services are used for, we will not go into the first place here.

    • Ihostingenvironment
    • Iloggerfactory
    • Ilogger<>
    • Iapplicationbuilderfactory
    • Ihttpcontextfactory
    • Ioptions<>
    • Diagnosticsource
    • Diagnosticlistener
    • Istartupfilter
    • Objectpoolprovider
    • IStartup

If we need these pre-registered services, we can use them in a way that is familiar to us in a way that relies on injections. As shown in the following code snippet, we use this predefined service directly in the startup configure method using method injection.

   1:public class Program
   2: {
   3: Public     static void Main (string[] args)
   4:     {
   5:         New Webhostbuilder ()
   6:             . Usekestrel ()
   7:             . Usestartup<startup> ()
   8:             . Build ()
   9:             . Run ();
  Ten:     }
  11:}
  12:public class Startup
  13: {     
  : Public     void Configure (
  :         iapplicationbuilder app,
  :         ihostingenvironment Environment,
  :         iloggerfactory Loggerfactory,
  :         ihttpcontextfactory Httpcontextfactory,
  :         Diagnosticsource Diagnosticsource,
  :         diagnosticlistener Diagnosticlistener)
  :     {
  :         app. Run (Async context =
  :         {
  :             context. Response.ContentType = "text/html";
  :             await the context. Response.writeasync ($ "iapplicationbuilder=>{app}<br/>");
  A:             await the context. Response.writeasync ($ "ihostingenvironment=>{environment}<br/>");
  :             await the context. Response.writeasync ($ "iloggerfactory=>{loggerfactory}<br/>");
  :             await the context. Response.writeasync ($ "ihttpcontextfactory=>{httpcontextfactory}<br/>");
  :             await the context. Response.writeasync ($ "diagnosticsource=>{diagnosticsource}<br/>");
  :             await the context. Response.writeasync ($ "diagnosticlistener=>{diagnosticlistener}");
  :         });
  :     }
  33:}

Since the middleware registered by the Configure method directly responds to the mapping of the registration type and the real type of the injected service, we access the application to get the output as shown below.

vi. Dependency Injection in ASP. NET Core MVC

For the ASP. NET MVC 5 machine and the previous version, the controller defined by default has a requirement that the controller type must have a default constructor with no parameters, otherwise the controller instance will not be activated. For ASP. NET Core MVC, which has a dependency injection capability, there is no limit to defining the controller. For pre-registered services, we can use them in a defined controller in a way that constructor injection is used. As a demonstration, we have rewritten the above application as follows.

   1:public class Program
   2: {
   3: Public     static void Main (string[] args)
   4:     {
   5:         New Webhostbuilder ()
   6:             . Usekestrel ()
   7:             . Configureservices (services=>services
   8:                 . Addsingleton<ifoo,foo> ()
   9:                 . Addsingleton<ibar,bar> ()
  Ten:                 . ADDMVC ())
  One:             . Configure (App=>app. USEMVC ())
  A:             . Build ()
  :             . Run ();
  :     }
  15:}
  
  17:public class HomeController
  18: {
  : Public     IFoo Foo {get; private set;}
  : Public     IBar Bar {get; private set;}
  
  : Public     HomeController (IFoo foo, IBar bar)
  :     {
  : This         . foo = foo;
  : This         . bar = bar;
  :     }
  
  :     [HttpGet ("/")]
  : Public     string Index ()
  :     {
  : This         . HttpContext.Response.ContentType = "text/html";
  :         return $ "ifoo=>{this. Foo}<br/>ibar=>{this. Bar} ";
  :     }       
  34:}

The above code has a significant difference from the previous one, that is, we simply do not have a startup type defined, We ported the functionality originally implemented in its two methods (Configureservices and configure) to the Webhostbuilder method of the same name, and the two forms of programming are actually equivalent. In addition to registering MVC-related services, the two services, Foo and bar, were registered in conjunction with the Configureservices method. As for another configure method, we directly call its extension method MVC to register the MVC-related middleware.

We define a default HomeController, which has a read-only property of two types, IFoo and Ibar, which is initialized by the arguments passed in by the constructor, and we know that this is the programmatic way of constructor injection. In the action method index, we still have the matching relationship between the registration type and the real type of the two services as the response content, so our access to the application will still get the output as shown below.

Original link: https://www.cnblogs.com/artech/p/dependency-injection-in-asp-net-core.html

To learn ASP., you must understand the ubiquitous "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.