Introduction to ABP (1): Building the Basic Structure of ABP Solutions

2020年9月15日 48点热度 0人点赞 0条评论
内容目录

Copyright © Author: whuanle, reproduction of articles on WeChat public account requires consent from "NCC Open Source Community".

Source Code Address: https://github.com/whuanle/AbpBaseStruct

Location of tutorial result code: https://github.com/whuanle/AbpBaseStruct/tree/master/src/1/AbpBase

This is the first chapter of the introductory ABP series. We will learn how to build a minimal ABP project structure, and later we will explain and develop step by step through this structure.

The first article of the ABP series, please support it more~

Building Project Basic Structure

Open VS 2019, create a solution, and then delete the project's projects to turn it into an empty solution. This series of tutorials will use AbpBase as the name prefix for the solution and projects.

In the solution, create a new solution folder named src to store the project source code.

Empty Solution

We are going to create a solution structure similar to the one shown below, except that there is no HttpApi.Client, and .EntityFrameCore is replaced with .Database.

Solution Structure

Now we will create the required project structure and understand the role of each project.

AbpBase.Domain.Shared

This project is the lowest level module and does not depend on other modules. It is mainly used to define various enumerations (enums), global constants (constants), static variables (static), startup dependency configurations (options), etc. It can also set a standard for the program, limiting various levels of modules to comply with this standard.

For example, to specify that the general parameter for API requests should not exceed 256 characters, we can write:

public static class Whole
{
    public const int MaxLength = 256;
}

[StringLength(maximumLength: Whole.MaxLength)]

In summary, this module is used to define various global, shared content (variables, enums, etc.), and generally does not include services.

Creation Process

Create a new .NET Standard project in the solution with the name AbpBase.Domain.Shared, and then add the Volo.Abp.Core package via Nuget, version 3.1.2.

shared

Then create a file named AbpBaseDomainSharedModule.cs with the following content:

using System;
using Volo.Abp.Modularity;

namespace AbpBase.Domain.Shared
{
    [DependsOn()]
    public class AbpBaseDomainSharedModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
        }
    }
}

In an ABP project, each module (project) must create a class that inherits from AbpModule to declare the structure and dependency injection of this module.

[DependsOn] is a dependency injection marker that indicates what services to inject for the module. Since .Domain.Shared does not depend on any module, it is currently left empty as [DependsOn()].

AbpBase.Domain

This project is used to define various classes for data transmission. For example, database entities, model classes for parameter passing, etc.

Creation Process

In the src folder of the solution, add a new project named AbpBase.Domain, and then reference the AbpBase.Domain.Shared project.

In the project, create a file named AbpBaseDomainModule.cs with the following content:

using AbpBase.Domain.Shared;
using Volo.Abp.Modularity;

namespace AbpBase.Domain
{
    [DependsOn(
        typeof(AbpBaseDomainSharedModule)
        )]
    public class AbpBaseDomainModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
        }
    }
}

AbpBase.Domain depends on AbpBase.Domain.Shared.

AbpBase.Application.Contracts

This module is mainly used to define interfaces, abstractions, and DTO objects. It is used to define various services without providing implementations.

Creation Process

In the src folder of the solution, create a new project named AbpBase.Application.Contracts, and then add a reference to the AbpBase.Domain project.

In the project, create a file named AbpBaseApplicationContractsModule.cs with the following content:

using AbpBase.Domain;
using Volo.Abp.Modularity;

namespace AbpBase.Application.Contracts
{
    [DependsOn(
       typeof(AbpBaseDomainModule)
   )]
    public class AbpBaseApplicationContractsModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
        }
    }
}

AbpBase.Database

This module is used to configure and define EFCore, Freesql, and other ORMs, as well as repositories, mainly handling database-related code.

Creation Process

Create a new project named AbpBase.Database in the src directory of the solution, and then add a reference to the AbpBase.Domain project.

In the project, create a file named AbpBaseDatabaseModule.cs with the following content:

using AbpBase.Domain;
using Volo.Abp.Modularity;

namespace AbpBase.Database
{
    [DependsOn(
  	 typeof(AbpBaseDomainModule)
    )]
    public class AbpBaseDatabaseModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {

        }
    }
}

ABP integrates EFCore by default, so we can use it directly. Here we won't handle database-related matters yet but will set up dependency injection in advance.

In the NuGet Package Manager, add the following four packages, all with version 3.1.2:

Volo.Abp.EntityFrameworkCore
Volo.Abp.EntityFrameworkCore.MySQL
Volo.Abp.EntityFrameworkCore.Sqlite
Volo.Abp.EntityFrameworkCore.SqlServer

Then modify the AbpBaseDatabaseModule.cs file to the following content:

using AbpBase.Domain;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.MySQL;
using Volo.Abp.EntityFrameworkCore.Sqlite;
using Volo.Abp.EntityFrameworkCore.SqlServer;
using Volo.Abp.Modularity;

namespace AbpBase.Database
{
    [DependsOn(
        typeof(AbpBaseDomainModule),
        typeof(AbpEntityFrameworkCoreModule),
        typeof(AbpEntityFrameworkCoreSqliteModule),
        typeof(AbpEntityFrameworkCoreSqlServerModule),
        typeof(AbpEntityFrameworkCoreMySQLModule)
        )]
    public class AbpBaseDatabaseModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
        }
    }
}

This way, our project will support the use of three types of databases.

AbpBase.Application

This module is used to implement interfaces and write various services.

Creation Process

In the src folder of the solution, create a new project named AbpBase.Application, and then add references to the AbpBase.Application.Contracts and AbpBase.Database projects.

In the project, create a file named AbpBaseApplicationModule.cs with the following content:

using AbpBase.Application.Contracts;
using AbpBase.Database;
using AbpBase.Domain;
using Volo.Abp.Modularity;

namespace AbpBase.Application
{
    [DependsOn(
        typeof(AbpBaseDomainModule),
        typeof(AbpBaseApplicationContractsModule),
        typeof(AbpBaseDatabaseModule)
    )]
    public class AbpBaseApplicationModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
        }
    }
}

AbpBase.HttpApi

This project is used to write API controllers.

Creation Process

Create a .NET Core Console Project named AbpBase.HttpApi, and add the Volo.Abp.AspNetCore.Mvc package via NuGet, version 3.1.2.

Then add references to the AbpBase.Application.Contracts and AbpBase.Application projects.

In the project, create a file named AbpBaseHttpApiModule.cs with the following content:

using AbpBase.Application;
using AbpBase.Application.Contracts;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;

namespace AbpBase.HttpApi
{
    [DependsOn(
        typeof(AbpAspNetCoreMvcModule),
        typeof(AbpBaseApplicationModule),
        typeof(AbpBaseApplicationContractsModule)
        )]
    public class AbpBaseHttpApiModule : AbpModule
    {

        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            Configure<AbpAspNetCoreMvcOptions>(options =>
            {
                options
                    .ConventionalControllers
                    .Create(typeof(AbpBaseHttpApiModule).Assembly, opts =>
                    {
                        opts.RootPath = "api/1.0";
                    });
            });
        }
    }
}

In the above, the module's ConfigureServices function creates the API service.

AbpBase.Web

This module is the top-level module, used to provide UI for user interaction, permission control, provide startup configuration information, control application runtime, etc.

Creation Process

In the src folder of the solution, create a new project named AbpBase.Web, the project should be an ASP.NET Core application and create the template as "Empty".

Add the Volo.Abp.Autofac package via the NuGet Package Manager, version 3.1.2, and then reference the AbpBase.Application and AbpBase.HttpApi projects.

In the project, create a file named AbpBaseWebModule.cs with the following content:

using AbpBase.Application;
using AbpBase.HttpApi;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;

namespace AbpBase.Web
{
    [DependsOn(
        typeof(AbpBaseApplicationModule),
        typeof(AbpAspNetCoreMvcModule),
        typeof(AbpBaseHttpApiModule)
        )]
    public class AbpBaseWebModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {

        }

        public override void OnApplicationInitialization(
            ApplicationInitializationContext context)
        {
            var app = context.GetApplicationBuilder();
            var env = context.GetEnvironment();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
            }

            app.UseStaticFiles();
            app.UseRouting();
            app.UseConfiguredEndpoints();
        }
    }
}

In the Program.cs file, add .UseAutofac()

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                }).UseAutofac();

Change the content of Startup.cs to:

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

namespace AbpBase.Web
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddApplication<AbpBaseWebModule>();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.InitializeApplication();
        }
    }
}

After completing the above steps, you will have a runnable ABP (WEB) application with a basic structure, and you can add an API for testing access.

AbpBase.HttpApi project, create a Controllers directory and add an API controller with the following content:

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc;

namespace AbpBase.Web.Controllers
{
    [ApiController]
    public class TestController : AbpController
    {
        [HttpGet(&quot;/T&quot;)]
        public string MyWebApi()
        {
            return &quot;Application started successfully!&quot;;
        }
    }
}

Then start the application and access https://localhost:5001/T. You will see the string displayed on the page, indicating a successful test.

Of course, this is just a very simple structure. We still need to add a series of services like cross-origin requests, authorization validation, dependency injection, Swagger, database access, etc. Later, we will learn the ABP framework and set up a complete practical project step by step, gradually progressing from easy to difficult.

Now, let’s introduce some code structures that appeared in the module above.

About ABP and Code Explanation

After completing the above steps, I believe you should have a general understanding of the ABP project. Below, we will introduce some concepts in ABP and analyze the code we encountered earlier.

Module

Let’s look at the ABP official website for the introduction to ABP:

The design provided by the ABP framework aims to support the construction of completely modular applications and systems.

Earlier, we established 7 projects, and I believe everyone has experienced the process of modular development.

ABP modularity means treating each project as a module, and each module needs to define a class that inherits from AbpModule, which will ultimately be integrated into the upper module.

[DependsOn]

When a module needs to use another module, it references the required module through the [DependsOn] attribute.

Configuring Services and Pipeline

Types that inherit from AbpModule can use ConfigureServices to configure services, such as dependency injection, database configuration, cross-origin requests, etc. The OnApplicationInitialization method is used to configure the middleware pipeline.

Of course, these two functions can be omitted, and you can directly write an empty Module:

    [DependsOn(
        typeof(AbpBaseDomainSharedModule)
        )]
    public class AbpBaseDomainModule : AbpModule
    {
    }

How Modules Associate

First, each module must define a class that inherits from AbpModule, and when one module wants to use another, it declares the reference using [DependsOn].

In the solution structure of this tutorial, AbpBase.Web is the top-level project that depends on three modules:

    [DependsOn(
        typeof(AbpBaseApplicationModule),
        typeof(AbpBaseHttpApiModule),
        typeof(AbpAspNetCoreMvcModule)
        )]

The AbpBaseApplicationModule module uses other modules, forming a reference chain. Readers can refer to the image at the beginning of the article.

Once the reference chain is formed, when the program starts, it will initialize starting from the bottom-level module. This initialization chain will sequentially call the ConfigureServices function of each module to gradually configure services for the program.

Domain.Shared -> Domain -> Application.Contras -> ....

You can print console information in the ConfigureServices function of each Module, then start the program and test it to see the order of printed messages.

For an introduction to ABP, you can refer to the documentation; I won’t copy the content here.

痴者工良

高级程序员劝退师

文章评论