淺入ABP(1):搭建基礎結構的 ABP 解決方案
阿新 • • 發佈:2020-09-16
# 淺入ABP(1):搭建基礎結構的 ABP 解決方案
[TOC]
版權護體©作者:痴者工良,微信公眾號轉載文章需要 《NCC開源社群》同意。
原始碼地址:https://github.com/whuanle/AbpBaseStruct
本教程結果程式碼位置:https://github.com/whuanle/AbpBaseStruct/tree/master/src/1/AbpBase
這裡是淺入 ABP 系列的第一章,我們將學習如果搭建一個極簡的 ABP 專案結構,後面我們通過這個結構,一步步來講解、一步步開發和完善。
ABP 系列的第一篇,請各位多多支援~
## 搭建專案基礎結構
開啟 VS 2019,建立一個解決方案,然後刪除解決方案的專案,變成空解決方案。本系列教程將使用 `AbpBase` 來命名解決方案和專案字首。
在解決方案中新建一個解決方案資料夾,名字為 `src`,用來存放專案原始碼。
![空解決方案](https://img2020.cnblogs.com/blog/1315495/202009/1315495-20200915215546998-321446722.png)
我們將要建立一個類似下圖這樣的層次結構的解決方案,只是沒有 `HttpApi.Client` ,另外`.EntityFrameCore` 改成了 `.Database`。
![解決方案結構](https://img2020.cnblogs.com/blog/1315495/202009/1315495-20200915215620324-1427390933.png)
下面我們來建立需要的專案結構,和了解每一個專案的作用。
### ApbBase.Domain.Shared
此專案是最底層的模組,且不依賴其他模組,主要用於定義各種列舉(`enums`)、全域性常量(`constants`)、靜態變數(static)、啟動依賴配置(options)等。還可以在此為程式設定一個標準,限制各個層次的模組都必須符合此標準的要求。
例如 規定API 請求的一般引數,字串長度不得大於 256 個字元,我們可以這樣寫:
```csharp
public static Whole
{
public const int MaxLength = 256;
}
[StringLength(maximumLength:Whole.MaxLength)]
```
總之,這個模組用於定義各種全域性的、共享的內容(變數、列舉等),一般不包含服務。
#### 建立過程
在解決方案中新建 `.NET Standard` 專案,名稱為 `ApbBase.Domain.Shared`,然後通過 `Nuget` 新增 `Volo.Abp.Core` 包,版本為 `3.1.2`。
![shared](https://img2020.cnblogs.com/blog/1315495/202009/1315495-20200915215643565-1855435491.png)
然後新建 一個 `AbpBaseDomainSharedModule.cs` 檔案,其內容如下:
```csharp
using System;
using Volo.Abp.Modularity;
namespace AbpBase.Domain.Shared
{
[DependsOn()]
public class AbpBaseDomainSharedModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
}
}
```
在 ABP 專案中,每一個模組(專案) 都要建立一個繼承 `AbpModule` 的 類,用於宣告此模組的結構、依賴注入等。
`[DependsOn]` 是依賴注入標記,代表要為模組注入什麼服務,因為 `.Domain.Shared` 不依賴任何模組,因此現在先留空,寫成 `[DependsOn()]` 。
### ApbBase.Domain
此專案用於定義各種用於傳遞資料的類。例如資料庫實體、用於做引數傳遞的模型類等。
#### 建立過程
我們在解決方案的`src` 資料夾,新增一個新的專案,名字為 `AbpBase.Domain`,然後引用 `ApbBase.Domain.Shared` 專案。
在專案中建立一個 `AbpBaseDomainModule.cs` 檔案,其內容如下:
```csharp
using AbpBase.Domain.Shared;
using Volo.Abp.Modularity;
namespace AbpBase.Domain
{
[DependsOn(
typeof(AbpBaseDomainSharedModule)
)]
public class AbpBaseDomainModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
}
}
```
`ApbBase.Domain` 依賴於 `ApbBase.Domain.Shared` 。
### ApbBase.Application.Contracts
主要用於定義介面、抽象和 DTO 物件。這個模組用於定義各種服務,但是不提供實現。
#### 建立過程
在解決方案的 `src` 資料夾,新建一個 `AbpBase.Application.Contracts` 專案,然後新增 `AbpBase.Domain` 專案引用。
在專案裡新建一個 `AbpBaseApplicationContractsModule` 檔案,其內容如下:
```csharp
using AbpBase.Domain;
using Volo.Abp.Modularity;
namespace AbpBase.Application.Contracts
{
[DependsOn(
typeof(AbpBaseDomainModule)
)]
public class AbpBaseApplicationContractsModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
}
}
```
### ApbBase.AbpBase.Database
此模組用於配置和定義 EFCore、Freesql 等 ORM,還有倉儲等,主要是處理資料庫相關的程式碼。
#### 建立過程
在解決方案 的 `src` 目錄新建一個 `AbpBase.Database` 專案,然後新增 `AbpBase.Domain` 專案引用。
在專案中新建一個 `AbpBaseDatabaseModule` 檔案,其內容如下:
```csharp
using AbpBase.Domain;
using Volo.Abp.Modularity;
namespace AbpBase.Database
{
[DependsOn(
typeof(AbpBaseDomainModule)
)]
public class AbpBaseDatabaseModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
}
}
```
ABP 裡面預設集成了 `EFCore` ,所以我們可以直接拿來使用,這裡我們先不處理資料庫相關的東西,但是先提前配好依賴注入。
在 Nuget 管理器中,新增下面四個包,版本都是 3.1.2 :
```csharp
Volo.Abp.EntityFrameworkCore
Volo.Abp.EntityFrameworkCore.MySQL
Volo.Abp.EntityFrameworkCore.Sqlite
Volo.Abp.EntityFrameworkCore.SqlServer
```
然後將 `AbpBaseDatabaseModule.cs` 檔案的內容修改成如下內容:
```csharp
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)
{
}
}
}
```
這樣,我們的專案將可以支援三種資料庫的使用。
### ApbBase.AbpBase.Application
此用於實現介面、編寫各種服務。
#### 建立過程
在解決方案的 `src` 資料夾,新建一個 `AbpBase.Application` 專案,然後新增 `AbpBase.Application.Contracts` 、 `AbpBase.Database` 專案引用。
在專案裡建立一個 `AbpBaseApplicationModule.cs` 檔案,其檔案內容如下:
```csharp
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)
{
}
}
}
```
### ApbBase.HttpApi
此專案用於編寫 API 控制器。
#### 建立過程
建立 一個 **.NET Core 控制檯專案**,名字為 `ApbBase.HttpApi`,通過 Nuget 新增 `Volo.Abp.AspNetCore.Mvc` 包,版本為 3.1.2。
然後新增 `AbpBase.Application.Contracts` 和 `AbpBase.Application` 兩個專案引用。
在專案裡面建立一個 `AbpBaseHttpApiModule.cs` 檔案,其內容如下:
```csharp
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(options =>
{
options
.ConventionalControllers
.Create(typeof(AbpBaseHttpApiModule).Assembly, opts =>
{
opts.RootPath = "api/1.0";
});
});
}
}
}
```
上面,模組的 `ConfigureServices` 函式裡面,建立了 API 服務。
### AbpBase.Web
此模組是最上層的模組,用於提供 UI 與使用者互動、許可權控制、提供啟動配置資訊、控制程式執行等。
#### 建立過程
在解決方案的 `src` 資料夾,新建一個 `AbpBase.Web ` 專案,**專案為 `ASP.NET Core` 程式**,並且建立模板為“空”。
通過 Nuget 管理器新增 `Volo.Abp.Autofac`,版本為 3.1.2,然後新增 `AbpBase.Application` 和 `ApbBase.HttpApi` 專案引用。
在專案裡面建立 `AbpBaseWebModule.cs` 檔案,其內容如下:
```csharp
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();
}
}
}
```
在 `Program.cs`檔案中 ,加上 `.UseAutofac()`
```csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup();
}).UseAutofac();
```
將 `Startup.cs` 的內容 改為:
```csharp
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace AbpBase.Web
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddApplication();
}
public void Configure(IApplicationBuilder app)
{
app.InitializeApplication();
}
}
}
```
完成上面的步驟後,你將得到一個可以啟動的、具有基礎結構的 ABP(WEB) 應用,你可以新增一個 API 來進行測試訪問。
在 `AbpBase.HttpApi` 專案中,建立一個 `COntrollers` 目錄,再新增一個 API 控制器,其內容如下:
```csharp
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 "應用啟動成功!";
}
}
}
```
然後啟動程式,訪問 [https://localhost:5001/T](https://localhost:5001/T),可以發現頁面顯示了字串,則測試成功。
當然,這只是一個非常簡單的結構,我們還需要新增專案跨域、授權驗證、依賴注入、swagger 、資料庫訪問等一系列的服務,後面我們將通過從易到難、逐步求精的方法來學習 ABP 框架和架設一個完整的實踐專案!
下面介紹一下上面模組中出現的一些程式碼結構。
## 關於ABP和程式碼解疑
完成上面的步驟後,相信你應該對 ABP 專案有了大致的認識,下面我們來介紹一下 ABP 中的一些概念以及前面出現到的一些程式碼解析。
### 模組
我們看一下 ABP 官網中關於 ABP 的介紹:
```
ABP 框架提供的設計旨在支援構建完全模組化的應用程式和系統
```
前面我們建立了 7 個專案,相信大家已經體驗到了模組化開發的過程。
ABP 模組化,就是將每個專案作為一個模組,然後每個模組中需要定義一個繼承 `AbpModule `的類,最終整合到上層模組中。
### [DependsOn]
一個模組要使用另一個模組時,通過 ` [DependsOn]` 特性來引用需要的模組。
### 配置服務和管道
繼承 `AbpModule` 的型別,可以使用 `ConfigureServices` 來配置服務,如依賴注入、資料庫配置、跨域等,`OnApplicationInitialization` 則用來配置中介軟體管道。
當然,這兩個函式都可以不寫,直接寫個空的 `Module`:
```csharp
[DependsOn(
typeof(AbpBaseDomainSharedModule)
)]
public class AbpBaseDomainModule : AbpModule
{
}
```
### 模組如何關聯
首先,每個模組都需要定義一個類來繼承 `AbpModule` ,然後一個模組要使用另一個模組,則通過 `[DependsOn]` 來宣告引用。
在本教程的解決方案結構中,` AbpBase.Web` 是最上層的專案,他依賴了三個模組:
```csharp
[DependsOn(
typeof(AbpBaseApplicationModule),
typeof(AbpBaseHttpApiModule),
typeof(AbpAspNetCoreMvcModule)
)]
```
而 `AbpBaseApplicationModule` 模組又使用了其他模組,這就形成了一個引用鏈,讀者可以看看文章開頭的圖片。
引用鍊形成後,程式啟動時,會順著這個鏈,從最底層的模組開始初始化。這個初始化鏈會依次呼叫模組的 `ConfigureServices` 函式,為程式逐漸配置服務。
```
Domain.Shared -> Domain -> Application.Contras -> ....
```
你可以在每個 `Module` 的 `ConfigureServices` 函式中列印控制檯資訊,然後啟動程式進行測試,看看列印順序。
對於 ABP 的介紹,大家可以看文件,這裡就不搬文件的內