建立 abp 專案
官方文件已經提供了非常詳細的新建專案嚮導。參考:https://docs.abp.io/en/abp/latest/Getting-Started-Create-Solution?UI=Blazor&DB=EF&Tiered=Yes
CLI 命令參考:https://docs.abp.io/en/abp/latest/CLI
我們使用 abp CLI 建立一個新專案。我使用 Blazor 來開發前端頁面,正好學一下。
abp new MainApp -u blazor
然後按照官方文件操作即可:https://docs.abp.io/en/abp/latest/Getting-Started-Running-Solution?UI=Blazor&DB=EF&Tiered=Yes
主要步驟是:
-
修改資料庫連線字串
-
執行 .DbMigrator 專案初始化資料庫並填充初始資料。
-
執行 .HttpApi.Host 專案
如果操作正確,我們應該能夠看到 Swagger 文件了。
如果同時啟動 .HttpApi.Host 和 .Blazor 專案,前端頁面也應該可以正常展示。基本的使用者登入、角色許可權都有了。
建立一個新模組
剛開始我是用 CLI 建立了一個新模組,然後手動把兩個專案的 solution 檔案整合到一塊,麻煩而且易出錯。後來發現原來 CLI 已經提供了將新模組新增到現有解決方案的命令,可參考:https://docs.abp.io/en/abp/latest/CLI#options-3
可以使用以下的命令:
abp add-module MyModule --new --add-to-solution-file
注意執行該命令的時候要在 MainApp 的目錄下。這樣 CLI 會在當前目錄下建立一個 modules 目錄來存放新模組的解決方案,同時把所有專案新增到 MainApp 的解決方案中,還會修改一些檔案,這樣我們就不用手動整合模組了。
新增新 Model
接下來繼續按照官方文件來新增新的 Model:https://docs.abp.io/en/abp/latest/Tutorials/Part-1
具體內容這裡就不展開了,可根據實際需要新增幾個 Model。
步驟大概是:
-
新增 Model
-
更新模組 MyModule.EntityFrameworkCore 專案中的 MyModuleDbContext.cs 檔案,新增相應的
DbSet
-
在 MyModuleDbContextModelCreatingExtensions.cs 中新增模型對映
為模組準備資料庫遷移
接下來就是本文的重點,如何為模組新增一個單獨的資料庫並實現資料庫遷移。
首先在 MainApp.EntityFrameworkCore 專案中新增目錄 EntityFrameworkCore\MyModule。在這個目錄中建立一個名為 MyModuleMigrationsDbContext.cs 的檔案。內容如下:
public class MyModuleMigrationsDbContext : AbpDbContext<MyModuleMigrationsDbContext> { public MyModuleMigrationsDbContext(DbContextOptions<MyModuleMigrationsDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ConfigureMyModule(); } }
然後新增一個名為 MyModuleMigrationsDbContextFactory.cs 的檔案:
public class MyModuleMigrationsDbContextFactory : IDesignTimeDbContextFactory<MyModuleMigrationsDbContext> { public MyModuleMigrationsDbContext CreateDbContext(string[] args) { var configuration = BuildConfiguration(); var builder = new DbContextOptionsBuilder<MyModuleMigrationsDbContext>() .UseSqlServer(configuration.GetConnectionString("MyModule")); return new MyModuleMigrationsDbContext(builder.Options); } private static IConfigurationRoot BuildConfiguration() { var builder = new ConfigurationBuilder() .SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../MainApp.DbMigrator/")) .AddJsonFile("appsettings.json", optional: false); return builder.Build(); } }
這兩個檔案與 MainApp 的 DbContext 內容是類似的,大家可以比較一下。因為模組也要從 appsettings.json 中讀取資料庫配置,因此我們需要修改 appsettings.json 中的資料庫連結字串,注意需要修改兩個位置:一個是 MainApp.DbMigrator 專案中的,另一個是 MainApp.HttpApi.Host 專案中的。仿照 MainApp
的連線字串新增一個名為 MyModule
的即可。這樣模組就可以有一個單獨的資料庫了。
執行模組資料庫遷移
建立了新的 Model 後,我們要對資料進行遷移,以應用這些更改。
將 terminal 導航到 MainApp.EntityFrameworkCore 目錄,執行以下命令:
dotnet ef migrations add migrationName --context MyModuleMigrationsDbContext --output-dir Migrations/MyModule
注意要指定要遷移的 DbContext,也就是 MyModuleMigrationsDbContext
。同時我們還將遷移檔案放在 Migrations/MyModule 目錄下,這樣不會與 MainApp 的遷移檔案混淆。
如果一切正常,我們就可以在指定目錄下看到生成的遷移檔案了。
執行以下命令以應用資料庫遷移:
dotnet ef database update --context MyModuleMigrationsDbContext
這樣模組的資料庫遷移就完成了。
其他設定
接下來按照官方文件繼續新增相應的 AppService 及其介面等。這樣我們的模組已經與 MainApp 是隔離的了,包括 Blazor 頁面也是在一個單獨的專案裡。
如果執行 .HttpApi.Host 沒有看到模組的 API,可以檢查下 MainApp.HttpApi.Host 專案中的 MainAppHttpApiHostModule.cs 檔案,看是否配置正確:
private void ConfigureConventionalControllers() { Configure<AbpAspNetCoreMvcOptions>(options => { options.ConventionalControllers.Create(typeof(MainAppApplicationModule).Assembly); // Add the below line options.ConventionalControllers.Create(typeof(MyModuleApplicationModule).Assembly); }); }
再次執行 .HttpApi.Host 和 .Blazor 專案,可以看到前端頁面已經新增了一個新模組的連結,只是內容頁是空的。接下來我們就可以在 MyModule 解決方案裡的 Blazor 專案中開發前端頁面了。
在新增 Model 後我還遇到過一個錯誤,如下圖所示:
Autofact.Core.DependencyResolutionException: 'An exception was thrown while activating Volo.Abp.IdentityServer.Grants.PersistedGrantStore ....'
乍一看還以為是 IdentityServer 的問題,其實不是。展開看 inner exception 就會發現這個是我們新增的 Dto 的 mapping 導致的。因為 Entity 是有 Id 的,但 CreateUpdateProductDto 沒有Id,所以 mapping 出錯了。如果遇到這種情況,可以將 Id 省略掉:
CreateMap<CreateUpdateProductDto, Product>().Ignore(x => x.Id);
學習了幾天感覺這個框架還是挺方便的,功能非常強大,但學習起來還是有一定難度的。框架各部分之間的依賴非常多,如果不仔細研究,很容易處處碰壁。好在官方文件寫的還是相對比較詳細的,只是部分文件還有空缺。希望官方以後補足吧。是否使用框架開發是一個兩難的問題,太依賴框架可能會失去對細節的把控,處處受制於框架的實現;不使用框架就得自己重複造輪子。只能見仁見智了。