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.
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
.
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
.
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("/T")]
public string MyWebApi()
{
return "Application started successfully!";
}
}
}
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.
文章评论