<<ABP Framework >> Dependency Injection

Source: Internet
Author: User

Document Directory

The content of this section:

    • What when Dependency Injection
      • The problem of the traditional way
      • Solution Solutions
        • Constructor injection Mode
        • Attribute injection mode
        • Dependency Injection Framework
    • ABP Dependency Injection Basics
      • Registration dependency
        • Contract injection
        • Auxiliary interface
        • Custom/Direct Registration
          • Using Iocmanager
          • Using the castle Windsor API
      • Analytical
      • Constructors and attribute injection
      • Iiocresolver and Iiocmanager
      • Other than that
        • Ishouldinitialize interface
      • ASP. NET MVC and ASP. NET Web Api Integration
      • ASP. NET Core Integration
      • Last Reminder

What is Dependency injection

If you already know about dependency injection concepts, constructors, and attribute injection, you can skip to the next topic.

Wikipedia: "Dependency injection is a software design pattern, where a dependent object (or client) requires one or more dependencies (or services) to be injected, or an incoming reference as part of its state. This mode separates the client's dependency creation from the client behavior, which makes the program design more loosely coupled, more in line with the dependency inversion and the single responsibility principle. It contrasts with the service locator pattern that the client understands dependencies. ”

Without the use of dependency injection technology, it is difficult to manage dependencies and develop a modular and well-structured application.

The problem of the traditional way

In an application, classes depend on each other. Suppose we have an application service that uses warehousing to insert entities into a database, in which case the application service class relies on the warehousing class, as follows:

 public  class   personappservice{ private   IPersonRepository _personrepository;  public   Personappservice () {_personrep                Ository  = new   Personrepository ();  public  void  Createperson (string  name, int   age) { var  person = new  person {name = name, age = a        GE};    _personrepository.insert (person); }}

Personappservice uses personreopsitory to insert a person into the database. The problem with this piece of code:

    • The service uses IPersonRepository references in the Createperson method, so this method relies on ipersonrepository. Although it replaces the Personrepository specific class, the service still relies on personrepository in its constructor. Components should depend on the interface and depend on the implementation, which is the principle of dependency inversion.
    • If the service creates personrepository itself, it can only be used in a particular implementation of ipersonrepository and cannot be used in other implementations of the interface, so separating the interface from the implementation becomes meaningless. Hard dependencies result in code tightening and low reusability.
    • In the future we may need to change the creation of personrepository, assuming that we want to make it a monomer (using only one instance instead of creating one instance per place), or if you want to create multiple implementations of the IPersonRepository class and then select one based on the condition, in which case We need to modify all classes that depend on IPersonRepository.
    • In this dependency, it is difficult (and even impossible) to test the service unit.

To overcome these problems, you can use Factory mode. Abstract the creation of warehousing. The code is as follows:

 public  class   personappservice{ private   IPersonRepository _personrepository;  public   Personappservice () {_personrep                Ository  = Personrepositoryfactory.create ();  public  void  Createperson (string  name, int   age) { var  person = new  person {name = name, age = a        GE};    _personrepository.insert (person); }}

Personrepositoryfactory is a static class that creates and returns a ipersonrepository. This is known as the service locator mode. The created problem is resolved, the Personappservice service does not know the implementation of creating ipersonrepository, and it is no longer dependent on the implementation of Personrepository. But there are still some problems:

    • At this point, Personappservice relies on personrepositoryfactory, which can be slightly accepting but still has a hard dependency.
    • It is tedious to write a factory/method for each warehousing or reliance.
    • It is still difficult to test because it is difficult for Personappservice to use ipersonrepository simulation implementations.

Solution Solutions

There are several best practices (patterns) on dependency injection.

Constructor injection Mode

The above example code can be rewritten as follows:

 public  class   personappservice{ private   IPersonRepository _personrepository;  public   Personappservice (     IPersonRepository personrepository) {_personrepository  = personrepository;  public  void  Createperson (string  name, int   age) { var  person = new  person {name = name, age = a        GE};    _personrepository.insert (person); }}

This is known as the constructor injection pattern. At this point, the Personappservice code does not know which class implements the IPersonRepository and how to create it. If you want to use Personappservice, first create a ipersonrepository, and then pass it to the Personappservice constructor, as follows:

var New personrepository (); var New Personappservice (repository);p Ersonservice.createperson ("Yunus Emre"19 );

Constructor injection is a perfect way to create a class that is independent of the creation of dependent objects. However, the above code also has some problems:

    • Creating a personappservice becomes difficult, considering that there are 4 dependencies, we have to create such 4 dependent objects and pass them to the Personappservice constructor.
    • Dependent classes may have other dependencies (here, personrepository may have other dependencies), so we have to create all personappservice dependencies, and dependencies, so go on ..., in this case, we can't even create a separate object, Because the dependency path is too complex.

Fortunately, there is a dependency injection framework that can automatically manage dependencies.

Attribute injection mode

Constructor injection provides a perfect way to inject dependent injection into a class, and in this way you cannot create an instance of a class that does not provide a dependency, and it is a strong way for you to explicitly declare all that you need to work correctly.

However, in some cases, some classes depend on other classes, but can also work without providing dependencies, which is often encountered in crosscutting concerns such as logs, a class can work without logs, but it can also write logs when you supply a logger to it. In this case, you can define an exposed dependency property, not a constructor. Think about it, we want to write a log in Personappservice, we can change it like this:

 Public classpersonappservice{ PublicILogger Logger {Get;Set; } Privateipersonrepository _personrepository;  PublicPersonappservice (ipersonrepository personrepository) {_personrepository=personrepository; Logger=nulllogger.instance; }     Public voidCreateperson (stringNameintAge ) {Logger.debug ("Inserting A new person to database with name ="+name); varperson =Newperson {name = name, age =Age };        _personrepository.insert (person); Logger.debug ("successfully inserted!"); }}

Nulllogger.instance is a singleton object that implements the ILogger, but does nothing on the implementation (log is not written.) It implements the ILogger with an empty method body). So at this point, if you set a logger to it after you create the Personappservice object, Personappservice can write the log as follows:

var New Personappservice (newnew  Log4netlogger ();p Ersonservice.createperson ("  Yunus Emre");

Suppose Log4netlogger implements ILogger and uses it to write logs log4net the library, so Personappservice can write logs. If we don't set up a logger, it doesn't write logs. So we can say that Personappservice's ILogger is an optional dependency.

Almost all of the dependency injection frameworks support attribute injection.

Dependency Injection Framework

There are a lot of dependency injection frameworks that can automatically parse dependencies, they can create all dependent objects (recursive dependencies), so you just have to write a constructor or attribute injection pattern, and the DI (dependency inversion) framework handles the rest of the work. Your class can even be independent of the DI Framework, where only a few lines of code or classes explicitly interact with the DI framework throughout your application.

ABP uses Castle Windsor as a dependency injection framework. It is one of the most mature di frameworks. There are many other frameworks, such as unity, Ninject, StructureMap, AUTOFAC, and so on.

When using a dependency injection framework, you first register your interface/class into the dependency injection framework, and then you can parse (create) an object. In Castle Windsor, the code resembles the following:

 var  container = new   WindsorContainer (); container. Register (component.for  <IPersonRepository> (). Implementedby<personrepository> (). Lifestyletransient (), component.for  <IPersonAppService> (). Implementedby<personappservice> (). Lifestyletransient ());  var  Personservice = container. Resolve<ipersonappservice> ();p Ersonservice.createperson (  " yunus Emre  " , 19 ); 

We first create the WindsorContainer container, then register the Personrepository and Personappservice with their interfaces, and we ask the container to create a ipersonappservice, It creates personappservice with dependencies and returns. Using the DI framework in this simple example may not be obvious, but consider that if you encounter many classes and dependencies in a real enterprise application, the situation is different. Of course, you can register dependencies elsewhere before use, or you can register only once when an app starts.

Register we also declare the object Lifecycle (life cycle) as ephemeral (transient), which means that when we parse this type of object, we create a new instance. There are other different life cycles, such as single cases.

ABP Dependency Injection Basics

When you write your application according to best practices and some conventions, the ABP has almost invisibly used the dependency injection framework.

Registration dependency

There are many different ways to register a class with a dependency injection system in the ABP. In most cases, it is sufficient to agree to register.

Contract Registration

The ABP automatically registers all warehousing, Domain Services, application services, MVC controllers, and Web API controllers as agreed. For example, you have a Ipersonappservice interface and a Personappservice class that implements the interface:

 Public Interface  iapplicationservice{    //... }publicclass  personappservice:ipersonappservice{    // ...}

The ABP automatically registers it because it implements the Iapplicationservice interface (an empty interface). Register as temporary (create an instance for each use). When you inject the Ipersonappservice interface (injected with a constructor) into a class, a Personappservice object is created and passed into the constructor automatically.

Naming conventions: It is important, for example, that you can change personappservice to mypersonappservice or other names with the suffix "personappservice", because Ipersonappservice is also the suffix, So no problem. But you can't name it "service", and if you do, Ipersonappservice can't automatically register (since registering to the ID frame instead of the interface), so you can only register manually.

The ABP can register assemblies by convention, and you can tell the ABP to register your assembly according to the Convention, which is fairly easy:

Iocmanager.registerassemblybyconvention (assembly.getexecutingassembly ());

Aseembly.getexecutingassembly () Gets a reference to the assembly that contains this code. You can also pass a different assembly to the Registerassemblybyconvention method, which is usually done when a module starts initializing. For more information, see the module system.

You can add your class by implementing the Iconventionalregisterer interface, writing your own contract registration class, and then calling the Iocmanager.addconventionalregisterer method in the pre-initialization of your module.

Auxiliary interface

You may want to register a specific class that does not conform to the Convention's registration rules, and the ABP provides a shortcut: Itransientdependency and isingletondependency interfaces. For example:

 Public Interface ipersonmanager{    //... }publicclass  Mypersonmanager:ipersonmanager, isingletondependency{     // ...}

In this way, you can easily register Mypersonmanager. When a ipersonmanager needs to be injected, it is used to Mypersonmanager. Note that the dependency is declared as a singleton. Therefore, only one instance of Mypersonmanager is created and the same instance is passed to all classes that need it. Created on first use and used throughout the lifecycle of your app.

Custom/Direct Registration

If the contract registration does not exactly match your situation, you can use Iocmanager or castle Windsor to register your class and dependencies.

Using Iocmanager

You can register dependencies with Iocmanager (typically in the pre-initialization of your module definition Class):

Iocmanager.register<imyservice, myservice> (dependencylifestyle.transient);

Using the castle Windsor API

You can use the Iiocmanger.ioccontainer property to access the Castle Windsor container and register dependencies. For example:

IocManager.IocContainer.Register (classes.fromthisassembly (). Basedon<imyspecialinterface> (). Lifestyleperthread (). Withserviceself ());

Please refer to the Windsor documentation for more information.

Analytical

In your application where you need to create an object using the IOC (inversion of Control) container (aka: Di framework), register your classes, dependencies, and lifetimes to tell the IOC container. The ABP provides several parsing methods.

Constructors and attribute injection

Best practice: You can use constructors and attribute injection to get the dependencies you need for your class. You should use this in any way possible. For example:

 Public classpersonappservice{ PublicILogger Logger {Get;Set; } Privateipersonrepository _personrepository;  PublicPersonappservice (ipersonrepository personrepository) {_personrepository=personrepository; Logger=nulllogger.instance; }     Public voidCreateperson (stringNameintAge ) {Logger.debug ("Inserting A new person to database with name ="+name); varperson =Newperson {name = name, age =Age };        _personrepository.insert (person); Logger.debug ("successfully inserted!"); }}

IPersonRepository is injected from the constructor, ILogger is injected from the public attribute. In this way, your code is completely unaware of the dependency injection system. This is the most appropriate way to use the DI system.

Iiocresolver and Iiocmanager

You may need to use direct parsing of your dependencies instead of constructors and attribute injection. This should be avoided as much as possible, but sometimes it is unavoidable. ABP provides some easy-to-use injection services, such as:

 Public classmysampleclass:itransientdependency{Private ReadOnlyIiocresolver _iocresolver;  PublicMysampleclass (Iiocresolver iocresolver) {_iocresolver=Iocresolver; }     Public voidDoIt () {//resolving, using and releasing manually        varPersonService1 = _iocresolver.resolve<personappservice>(); Personservice1.createperson (Newcreatepersoninput {Name ="Yunus", Surname ="Emre" });        _iocresolver.release (PersonService1); //resolving and using in a safe        using(varPersonService2 = _iocresolver.resolveasdisposable<personappservice>()) {PersonService2.Object.CreatePerson (Newcreatepersoninput {Name ="Yunus", Surname ="Emre" }); }    }}

A mysampleclass example in an application that injects iiocresolver with a constructor and uses it to parse and release objects. The Resolve method has several overloads that can be used to resolve, and release releases the component (object). If you manually parse an object, remember to call release, or your app might have a memory leak. To ensure that the object is disposed, use resolveasdisposable as much as possible (as shown in the example above), which automatically calls release at the end of the using block.

If you want to parse dependencies directly using the IOC container (Castle Windsor), you can inject Iiocmanager with the constructor and use the Iiocmanager.ioccontainer property. If you are in a static context, or are not likely to inject Iiocmanager, the final option is: You can use the Singleton object iocmanager.instance anywhere, but it's not easy to test using your code in this way.

Other than that

Ishouldinitialize interface

Some classes need to be initialized before the first use, and Ishouldinitialize has a initialize method that, if you implement it, automatically calls your Initialize method after you create your object (before you use it). Of course, you should inject/parse this object so that this feature works.

ASP. NET MVC and ASP. NET Web Api Integration

We must invoke the dependency injection system to parse the root object on the dependency graph. In an ASP. NET MVC application, it is usually a controller class. We can also use constructor injection and attribute injection mode in the controller. When a request arrives in our application, the controller is created with the IOC container and all dependent recursive parsing. So who's going to do it? Automatically done by the ABP by extending the default controller factory of MVC. Similarly, the ASP. NET Web API is the same. And you don't have to have relationships to create and destroy objects.

ASP. NET Core Integration

Temporary brief

Last Reminder

As long as you follow the above rules and structure, ABP simplifies and automatically uses dependency injection. In most cases you don't have to do more, but as long as you need, you can use Castle Windsor all the ability to perform any task (like custom registration, injection hooks, interceptors, etc.).

<<ABP Framework >> 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.