. Net Core MVC Web Development (Ninesky) 2.3, Project architecture tuning-control inversion and dependency injection usage

Source: Internet
Author: User

Re-adjust the project structure is because and group of friends Dezhou a chat, my original idea is the project as far as possible to do simple points do not complicate, only use the DbContext injection, the other is not written interface coupling is very high. After chatting with Dezhou, I thought about it carefully, or decoupling it, originally according to the software design pattern should be high cohesion low coupling, low coupling makes the project module independent of other modules, increased maintainability and portability!

Note : The blog in front of the detailed record of not every step of the project operation, in fact, write a blog to take time, and the whole piece of blog a lot of useless information. For MVC will add the controller, add the view, add the class these are the most basic requirements, and the previous blog is written, the back also no longer detail these things, mainly write some ideas and key code, specific content in the form of source code in the post-blog to provide download.

First, the default project structure

Let's take a look at the project structure created by default for vs2015.

Projects in the model, data access, business logic and view related content are in a project, view, business logic and display tightly coupled, before looking at nothing, to the content of the project becomes larger, especially after a period of time to update the project, in the words of chaos, sometimes a small change resulting in the entire project export error , the headache is extreme.

Two or three-tier architecture

Let's look at the three-tier architecture:

    • User Interface Presentation layer (USL)
    • Business Logic Layer (BLL)
    • Data access Layer (DAL)

The three-tier architecture is mainly to make the project structure clearer, the division of labor is more clear, conducive to later maintenance and upgrade. It does not necessarily improve performance because the main program module can only wait when the subroutine module does not finish. This means that dividing the application hierarchy will result in some loss of execution speed. But from the team development efficiency angle and maintainability is easy to carry out task assignment, maintainability is high.

According to the three-layer idea, the controller (C) and the View (V) in MVC are all processing interface display related content belongs to the user interface presentation layer (USL), the Model (M) is the data exchanged between controller and view, so the MVC framework should belong to the user interface presentation layer in layer three.

The data Access layer (DAL) and the Business Logic layer (BLL), the business logic layer, and the user interface presentation layer (USL) also exchange data, and simply separate the model (M) from the data that is exchanged between the controller and the view, and three levels. Three, high coupling

We look at the current project structure of Ninesky, such as:

Consists of four items:

Ninesky.datalibrary is the data access layer that provides support for database access.

Ninesky.base is the business logic layer that is responsible for the processing of business logic.

The Ninesky.web user Interface Presentation layer (USL), which is responsible for displaying the logical processing of pages and display items.

Ninesky.models are data entities that are exchanged between layers.

From the above you can see that the project is layered according to three layers of thought. PS: A group of friends asked why the project name is called Datalibrary, Base, not called DAL,BLL? This may be the cause of obsessive-compulsive disorder, I looked at the DAL,BLL project name is particularly uncomfortable, changed a name I like, in fact, the function is the same.

And look at the project call

Take a look at Ninesky.base's Categoryservice class.

Position 1 in the code declares the class Categoryrepository, which is a class in Ninesky.datalibrary. Location 2 instantiates the project, and at position 3 we call the Find method of this class directly. From the above you can see that the Categoryservice class is dependent on the Categoryrepository class, and the Ninesky.base project is dependent on the Ninesky.datalibrary project. The class of one project calls the method of another project class exactly, then they are high coupling. A high-coupling is a problem in software design, it is necessary to decouple, the dependent implementation of the code into the logic of dependency, it is necessary to introduce an abstraction layer (usually interface). Iv. Dependency Interface

We add a DLL project ninesky.interfacedatalibrary and add a reference to the Ninesky.interfacedatalibrary project to Ninesky.datalibrary.

Add Interfacebaserepository interface to Ninesky.interfacedatalibrary project

1 usingSystem;2 usingSystem.Collections.Generic;3 usingSystem.Linq.Expressions;4 usingSystem.Threading.Tasks;5 6 namespaceNinesky.interfacedatalibrary7{8     // <summary>9     /// Warehousing base class interfaceTen     // </summary> One     /// <typeparam name= "T" ></typeparam> A      Public Interfaceinterfacebaserepository<t> where T:class -{ -         // <summary> the         /// query [excluding navigation properties] -         // </summary> -         /// <param name= "predicate" > query expression </param> -         /// <returns> entities </returns> +T Find (Expression<func<t,BOOL>> predicate); -} +}
View CodeModify the Baserepository code to let baserepository inherit Interfacebaserepository
1 usingSystem;2 usingSystem.Collections.Generic;3 usingSystem.Linq;4 usingSystem.Linq.Expressions;5 usingMicrosoft.entityframeworkcore;6 usingNinesky.interfacedatalibrary;7 8 namespaceNinesky.datalibrary9{Ten     // <summary> One     /// Warehousing base class A     // </summary> -      Public classBaserepository<t>:interfacebaserepository<t> where T:class
 -{ the         protectedDbContext _dbcontext; -          PublicBaserepository (DbContext DbContext) -{ -_dbcontext = DbContext; +} -  +         // <summary> A         /// query [excluding navigation properties] at         // </summary> -         /// <param name= "predicate" > query expression </param> -         /// <returns> entities </returns> -          Public VirtualT Find (Expression<func<t,BOOL>> predicate) -{ -             return_dbcontext.set<t> (). Singleordefault (predicate); in} -} to} + 
View Code

Referencing Ninesky.interfacedatalibrary in the Ninesky.base project, we are modifying the Categoryservice code

1      Public classCategoryservice2{3         PrivateInterfacebaserepository<category> _categoryrepository;4          PublicCategoryservice (DbContext DbContext)5{6_categoryrepository =NewBaserepository<category> (DbContext);7}8 9         // <summary>Ten         /// Find One         // </summary> A         /// <param name= "Id" > Column id</param> -         // <returns></returns> -          PublicCategory Find (intID) the{ -             return_categoryrepository.find (c = C.categoryid = = Id); -} -}
View Code

A variable of type interfacebaserepository is declared at the beginning of the code, and Interfacebaserepository is instantiated as a baserepository type in the constructor.

Now the Ninesky.base project is still dependent on the project ninesky.datalibrary, and there is no decoupling, if you want to remove the dependence of many ninesky.datalibrary to find a way to transfer the interface of the instantiation of the project.

V. Inversion of control

Control inversion is the move of dependent creation to the outside of the class. Then we modify the constructor of the Categoryservice class.

The constructor passed an interface type parameter, and now the class has no relationship with ninesky.datalibrary, you can delete the reference to the Ninesky.datalibrary project.

And now there's a new question: How does control inversion work, and how do I instantiate an interface?

Common workarounds include service locators and dependency injection.

Six, service locator

A service locator is a centralized instantiation of a class.

Create a separate project, add a reference to the project, and then instantiate in the factory class centrally.

  1publicclass Factory  2 {  3public      Interfacebaserepository<category> getbaserepository ()  4     {  5         return New Baserepository<category> ();   6     }   7 }
View Code

The benefit of the service locator is that the implementation is simple and can create a global service locator with the disadvantage that the component requirements are opaque. Ninesky uses another implementation of control inversion: Dependency Injection.

Vii. Dependency Injection.

The previous injection in. NET MVC was a hassle, fortunately. NET Core MVC has built-in support for dependency injection.

Modify the Categorycontroller code, using the constructor injection. Here, for example, the simple class that uses the data storage layer directly in the controller is injected without using the class of the business logic layer.

In the controller, the constructor is injected, and the Categoryservice parameters are passed through the constructor function.

1      Public classCategorycontroller:controller2{3         // <summary>4         /// Data Context5         // </summary>6         PrivateNineskydbcontext _dbcontext;7 8         // <summary>9         /// column ServicesTen         // </summary> One         PrivateCategoryservice _categoryservice; A  -          PublicCategorycontroller (Categoryservice categoryservice) -{ the_categoryservice = Categoryservice; -} -  -         // <summary> +         /// View Section -         // </summary> +         /// <param name= "id" > Column id</param> A         // <returns></returns> at[Route ("/category/{id:int}")] -          PublicIactionresult Index (intId -{ -var category = _categoryservice.find (ID); -             if(Category = =NULL)returnView ("Error",Newmodels.error {Title = "error Message", Name="column does not exist", description="Access ID is ""+id+""Error occurred in the column, the column does not exist. " }); -             Switch(category. Type) in{ -                  CaseCategorytype.general: to                     if(category. General = =NULL)returnView ("Error",NewModels.error {title= "error Message", Name="column data is not complete", description="can't find the column ""+category. Name+ ""For more information. " }); +                     returnView (category. General.view, category); -                  CaseCategorytype.page: the                     if(category. Page = =NULL)returnView ("Error",Newmodels.error {Title = "error Message", Name ="column data is not complete", Description ="can't find the column ""+ category. Name + ""For more information. " }); *                     returnView (category. Page.view, category); $                  CaseCategorytype.link:Panax Notoginseng                     if(category. Link = =NULL)returnView ("Error",Newmodels.error {Title = "error Message", Name ="column data is not complete", Description ="can't find the column ""+ category. Name + ""For more information. " }); -                     returnRedirect (category. Link.url); the                 default: +                     returnView ("Error",Newmodels.error {Title = "error Message", Name ="Column data Error", Description ="column ""+ category. Name + ""type error. " }); A  the} +} -}
View Code

Then we enter, the Web startup class startup is injected. Such as:

The first red box is in the "2.1, column of the foreground display" in the context injected;

The second red box to the fourth red box is what is added today.

The third red box injects a interfacebaserepository interface, which is instantiated using Baserepository.

The contents of the second red box are because Baserepository is instantiated with a parameter of type DbContext. The required parameters must be injected in front of the injection, and the system will not automatically nineskydbcontext converted to DbContext. So a parameter of type DbContext must be injected.

The fourth red box is injected into the categoryservice. Here categoryservice can also use the interface, time reason is not written.

As you can see, Categoryservice has lifted its dependence on baserepository, There is no dependency on ninesky.datalibrary in the Ninesky.base project, the instantiation of the class is injected into the Web project, and the Web project relies on the ninesky.datalibrary. The same approach can also be implemented to decouple the Ninesky.base project from the Web project.

If you want to completely disassociate the Ninesky.web project from the Ninesky.datalibrary and ninesky.base projects, you can use a configuration file to load it, not this time.

F5 in the browser, you can see that the data is taken out, just because the data storage layer's code does not contain navigation properties so the data is incomplete.

Viii. Other code escrow address: Https://git.oschina.net/ninesky/Ninesky

Article published address: http://www.ninesky.cn

http://mzwhj.cnblogs.com/

Code package Download: Ninesky2.3 Project schema tuning-control inversion and use of dependency injection. rar

Back to Catalog

. Net Core MVC Web Development (Ninesky) 2.3, Project architecture tuning-control inversion and dependency injection usage

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.