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

痴者工良 發表於 2020-09-15

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

版權護體©作者:痴者工良,微信公眾號轉載文章需要 《NCC開源社群》同意。

原始碼地址:https://github.com/whuanle/AbpBaseStruct

本教程結果程式碼位置:https://github.com/whuanle/AbpBaseStruct/tree/master/src/1/AbpBase

這裡是淺入 ABP 系列的第一章,我們將學習如果搭建一個極簡的 ABP 專案結構,後面我們通過這個結構,一步步來講解、一步步開發和完善。

ABP 系列的第一篇,請各位多多支援~

搭建專案基礎結構

開啟 VS 2019,建立一個解決方案,然後刪除解決方案的專案,變成空解決方案。本系列教程將使用 AbpBase 來命名解決方案和專案字首。

在解決方案中新建一個解決方案資料夾,名字為 src,用來存放專案原始碼。

空解決方案

我們將要建立一個類似下圖這樣的層次結構的解決方案,只是沒有 HttpApi.Client ,另外.EntityFrameCore 改成了 .Database

解決方案結構

下面我們來建立需要的專案結構,和了解每一個專案的作用。

ApbBase.Domain.Shared

此專案是最底層的模組,且不依賴其他模組,主要用於定義各種列舉(enums)、全域性常量(constants)、靜態變數(static)、啟動依賴配置(options)等。還可以在此為程式設定一個標準,限制各個層次的模組都必須符合此標準的要求。

例如 規定API 請求的一般引數,字串長度不得大於 256 個字元,我們可以這樣寫:

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

然後新建 一個 AbpBaseDomainSharedModule.cs 檔案,其內容如下:

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 檔案,其內容如下:

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 檔案,其內容如下:

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 檔案,其內容如下:

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 :

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

然後將 AbpBaseDatabaseModule.cs 檔案的內容修改成如下內容:

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.ContractsAbpBase.Database 專案引用。

在專案裡建立一個 AbpBaseApplicationModule.cs 檔案,其檔案內容如下:

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.ContractsAbpBase.Application 兩個專案引用。

在專案裡面建立一個 AbpBaseHttpApiModule.cs 檔案,其內容如下:

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";
                    });
            });
        }
    }
}

上面,模組的 ConfigureServices 函式裡面,建立了 API 服務。

AbpBase.Web

此模組是最上層的模組,用於提供 UI 與使用者互動、許可權控制、提供啟動配置資訊、控制程式執行等。

建立過程

在解決方案的 src 資料夾,新建一個 AbpBase.Web 專案,專案為 ASP.NET Core 程式,並且建立模板為“空”。

通過 Nuget 管理器新增 Volo.Abp.Autofac,版本為 3.1.2,然後新增 AbpBase.ApplicationApbBase.HttpApi 專案引用。

在專案裡面建立 AbpBaseWebModule.cs 檔案,其內容如下:

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()

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

Startup.cs 的內容 改為:

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();
        }
    }
}

完成上面的步驟後,你將得到一個可以啟動的、具有基礎結構的 ABP(WEB) 應用,你可以新增一個 API 來進行測試訪問。

AbpBase.HttpApi 專案中,建立一個 COntrollers 目錄,再新增一個 API 控制器,其內容如下:

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,可以發現頁面顯示了字串,則測試成功。

當然,這只是一個非常簡單的結構,我們還需要新增專案跨域、授權驗證、依賴注入、swagger 、資料庫訪問等一系列的服務,後面我們將通過從易到難、逐步求精的方法來學習 ABP 框架和架設一個完整的實踐專案!

下面介紹一下上面模組中出現的一些程式碼結構。

關於ABP和程式碼解疑

完成上面的步驟後,相信你應該對 ABP 專案有了大致的認識,下面我們來介紹一下 ABP 中的一些概念以及前面出現到的一些程式碼解析。

模組

我們看一下 ABP 官網中關於 ABP 的介紹:

ABP 框架提供的設計旨在支援構建完全模組化的應用程式和系統

前面我們建立了 7 個專案,相信大家已經體驗到了模組化開發的過程。

ABP 模組化,就是將每個專案作為一個模組,然後每個模組中需要定義一個繼承 AbpModule 的類,最終整合到上層模組中。

[DependsOn]

一個模組要使用另一個模組時,通過 [DependsOn] 特性來引用需要的模組。

配置服務和管道

繼承 AbpModule 的型別,可以使用 ConfigureServices 來配置服務,如依賴注入、資料庫配置、跨域等,OnApplicationInitialization 則用來配置中介軟體管道。

當然,這兩個函式都可以不寫,直接寫個空的 Module

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

模組如何關聯

首先,每個模組都需要定義一個類來繼承 AbpModule ,然後一個模組要使用另一個模組,則通過 [DependsOn] 來宣告引用。

在本教程的解決方案結構中, AbpBase.Web 是最上層的專案,他依賴了三個模組:

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

AbpBaseApplicationModule 模組又使用了其他模組,這就形成了一個引用鏈,讀者可以看看文章開頭的圖片。

引用鍊形成後,程式啟動時,會順著這個鏈,從最底層的模組開始初始化。這個初始化鏈會依次呼叫模組的 ConfigureServices 函式,為程式逐漸配置服務。

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

你可以在每個 ModuleConfigureServices 函式中列印控制檯資訊,然後啟動程式進行測試,看看列印順序。

對於 ABP 的介紹,大家可以看文件,這裡就不搬文件的內容了。