1. 程式人生 > >淺入ABP(1):搭建基礎結構的 ABP 解決方案

淺入ABP(1):搭建基礎結構的 ABP 解決方案

# 淺入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 的介紹,大家可以看文件,這裡就不搬文件的內