日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

初识ABP vNext(11):聚合根、仓储、领域服务、应用服务、Blob储存

發布時間:2023/12/4 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 初识ABP vNext(11):聚合根、仓储、领域服务、应用服务、Blob储存 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊上方藍字"小黑在哪里"關注我吧

  • 聚合根

  • 倉儲

  • 領域服務

    • BLOB儲存

  • 應用服務

  • 單元測試

  • 模塊引用

前言

在前兩節中介紹了ABP模塊開發的基本步驟,試著實現了一個簡單的文件管理模塊;功能很簡單,就是基于本地文件系統來完成文件的讀寫操作,數據也并沒有保存到數據庫,所以之前只簡單使用了應用服務,并沒有用到領域層。而在DDD中領域層是非常重要的一層,其中包含了實體,聚合根,領域服務,倉儲等等,復雜的業務邏輯也應該在領域層來實現。本篇來完善一下文件管理模塊,將文件記錄保存到數據庫,并使用ABP BLOB系統來完成文件的存儲。

開始

聚合根

首先從實體模型開始,建立File實體。按照DDD的思路,這里的File應該是一個聚合根

\modules\file-management\src\Xhznl.FileManagement.Domain\Files\File.cs:

public?class?File?:?FullAuditedAggregateRoot<Guid>,?IMultiTenant {public?virtual?Guid??TenantId?{?get;?protected?set;?}[NotNull]public?virtual?string?FileName?{?get;?protected?set;?}[NotNull]public?virtual?string?BlobName?{?get;?protected?set;?}public?virtual?long?ByteSize?{?get;?protected?set;?}protected?File()?{?}public?File(Guid?id,?Guid??tenantId,?[NotNull]?string?fileName,?[NotNull]?string?blobName,?long?byteSize)?:?base(id){TenantId?=?tenantId;FileName?=?Check.NotNullOrWhiteSpace(fileName,?nameof(fileName));BlobName?=?Check.NotNullOrWhiteSpace(blobName,?nameof(blobName));ByteSize?=?byteSize;} }

在DbContext中添加DbSet

\modules\file-management\src\Xhznl.FileManagement.EntityFrameworkCore\EntityFrameworkCore\IFileManagementDbContext.cs:

public?interface?IFileManagementDbContext?:?IEfCoreDbContext {DbSet<File>?Files?{?get;?} }

\modules\file-management\src\Xhznl.FileManagement.EntityFrameworkCore\EntityFrameworkCore\FileManagementDbContext.cs:

public?class?FileManagementDbContext?:?AbpDbContext<FileManagementDbContext>,?IFileManagementDbContext {public?DbSet<File>?Files?{?get;?set;?}...... }

配置實體

\modules\file-management\src\Xhznl.FileManagement.EntityFrameworkCore\EntityFrameworkCore\FileManagementDbContextModelCreatingExtensions.cs:

public?static?void?ConfigureFileManagement(this?ModelBuilder?builder,Action<FileManagementModelBuilderConfigurationOptions>?optionsAction?=?null) {......builder.Entity<File>(b?=>{//Configure?table?&?schema?nameb.ToTable(options.TablePrefix?+?"Files",?options.Schema);b.ConfigureByConvention();//Propertiesb.Property(q?=>?q.FileName).IsRequired().HasMaxLength(FileConsts.MaxFileNameLength);b.Property(q?=>?q.BlobName).IsRequired().HasMaxLength(FileConsts.MaxBlobNameLength);b.Property(q?=>?q.ByteSize).IsRequired();}); }

倉儲

ABP為每個聚合根或實體提供了 默認的通用(泛型)倉儲 ,其中包含了標準的CRUD操作,注入IRepository<TEntity, TKey>即可使用。通常來說默認倉儲就夠用了,有特殊需求時也可以自定義倉儲。

定義倉儲接口

\modules\file-management\src\Xhznl.FileManagement.Domain\Files\IFileRepository.cs:

public?interface?IFileRepository?:?IRepository<File,?Guid> {Task<File>?FindByBlobNameAsync(string?blobName); }

倉儲實現

\modules\file-management\src\Xhznl.FileManagement.EntityFrameworkCore\Files\EfCoreFileRepository.cs:

public?class?EfCoreFileRepository?:?EfCoreRepository<IFileManagementDbContext,?File,?Guid>,?IFileRepository {public?EfCoreFileRepository(IDbContextProvider<IFileManagementDbContext>?dbContextProvider)?:?base(dbContextProvider){}public?async?Task<File>?FindByBlobNameAsync(string?blobName){Check.NotNullOrWhiteSpace(blobName,?nameof(blobName));return?await?DbSet.FirstOrDefaultAsync(p?=>?p.BlobName?==?blobName);} }

注冊倉儲

\modules\file-management\src\Xhznl.FileManagement.EntityFrameworkCore\EntityFrameworkCore\FileManagementEntityFrameworkCoreModule.cs:

public?class?FileManagementEntityFrameworkCoreModule?:?AbpModule {public?override?void?ConfigureServices(ServiceConfigurationContext?context){context.Services.AddAbpDbContext<FileManagementDbContext>(options?=>{options.AddRepository<File,?EfCoreFileRepository>();});} }

領域服務

定義領域服務接口

\modules\file-management\src\Xhznl.FileManagement.Domain\Files\IFileManager.cs:

public?interface?IFileManager?:?IDomainService {Task<File>?FindByBlobNameAsync(string?blobName);Task<File>?CreateAsync(string?fileName,?byte[]?bytes);Task<byte[]>?GetBlobAsync(string?blobName); }

在實現領域服務之前,先來安裝一下ABP Blob系統核心包,因為我要使用blob來存儲文件,Volo.Abp.BlobStoring包是必不可少的。

BLOB儲存

BLOB(binary large object):大型二進制對象;關于BLOB可以參考 BLOB 存儲[1] ,這里不多介紹。

安裝Volo.Abp.BlobStoring,在Domain項目目錄下執行:abp add-package Volo.Abp.BlobStoring

Volo.Abp.BlobStoring是BLOB的核心包,它僅包含BLOB的一些基本抽象,想要BLOB系統正常工作,還需要為它配置一個提供程序;這個提供程序暫時不管,將來由模塊的具體使用者去提供。這樣的好處是模塊不依賴特定存儲提供程序,使用者可以隨意的指定存儲到阿里云,Azure,或者文件系統等等。。。

領域服務實現

\modules\file-management\src\Xhznl.FileManagement.Domain\Files\FileManager.cs:

public?class?FileManager?:?DomainService,?IFileManager {protected?IFileRepository?FileRepository?{?get;?}protected?IBlobContainer?BlobContainer?{?get;?}public?FileManager(IFileRepository?fileRepository,?IBlobContainer?blobContainer){FileRepository?=?fileRepository;BlobContainer?=?blobContainer;}public?virtual?async?Task<File>?FindByBlobNameAsync(string?blobName){Check.NotNullOrWhiteSpace(blobName,?nameof(blobName));return?await?FileRepository.FindByBlobNameAsync(blobName);}public?virtual?async?Task<File>?CreateAsync(string?fileName,?byte[]?bytes){Check.NotNullOrWhiteSpace(fileName,?nameof(fileName));var?blobName?=?Guid.NewGuid().ToString("N");var?file?=?await?FileRepository.InsertAsync(new?File(GuidGenerator.Create(),?CurrentTenant.Id,?fileName,?blobName,?bytes.Length));await?BlobContainer.SaveAsync(blobName,?bytes);return?file;}public?virtual?async?Task<byte[]>?GetBlobAsync(string?blobName){Check.NotNullOrWhiteSpace(blobName,?nameof(blobName));return?await?BlobContainer.GetAllBytesAsync(blobName);} }

應用服務

接下來修改一下應用服務,應用服務通常沒有太多業務邏輯,其調用領域服務來完成業務。

應用服務接口

\modules\file-management\src\Xhznl.FileManagement.Application.Contracts\Files\IFileAppService.cs:

public?interface?IFileAppService?:?IApplicationService {Task<FileDto>?FindByBlobNameAsync(string?blobName);Task<string>?CreateAsync(FileDto?input); }

應用服務實現

\modules\file-management\src\Xhznl.FileManagement.Application\Files\FileAppService.cs:

public?class?FileAppService?:?FileManagementAppService,?IFileAppService {protected?IFileManager?FileManager?{?get;?}public?FileAppService(IFileManager?fileManager){FileManager?=?fileManager;}public?virtual?async?Task<FileDto>?FindByBlobNameAsync(string?blobName){Check.NotNullOrWhiteSpace(blobName,?nameof(blobName));var?file?=?await?FileManager.FindByBlobNameAsync(blobName);var?bytes?=?await?FileManager.GetBlobAsync(blobName);return?new?FileDto{Bytes?=?bytes,FileName?=?file.FileName};}[Authorize]public?virtual?async?Task<string>?CreateAsync(FileDto?input){await?CheckFile(input);var?file?=?await?FileManager.CreateAsync(input.FileName,?input.Bytes);return?file.BlobName;}protected?virtual?async?Task?CheckFile(FileDto?input){if?(input.Bytes.IsNullOrEmpty()){throw?new?AbpValidationException("Bytes?can?not?be?null?or?empty!",new?List<ValidationResult>{new?ValidationResult("Bytes?can?not?be?null?or?empty!",?new[]?{"Bytes"})});}var?allowedMaxFileSize?=?await?SettingProvider.GetAsync<int>(FileManagementSettings.AllowedMaxFileSize);//kbvar?allowedUploadFormats?=?(await?SettingProvider.GetOrNullAsync(FileManagementSettings.AllowedUploadFormats))?.Split(",",?StringSplitOptions.RemoveEmptyEntries);if?(input.Bytes.Length?>?allowedMaxFileSize?*?1024){throw?new?UserFriendlyException(L["FileManagement.ExceedsTheMaximumSize",?allowedMaxFileSize]);}if?(allowedUploadFormats?==?null?||?!allowedUploadFormats.Contains(Path.GetExtension(input.FileName))){throw?new?UserFriendlyException(L["FileManagement.NotValidFormat"]);}} }

API控制器

最后記得將服務接口暴露出去,我這里是自己編寫Controller,你也可以使用ABP的自動API控制器來完成,請參考 自動API控制器[2]

\modules\file-management\src\Xhznl.FileManagement.HttpApi\Files\FileController.cs:

[RemoteService] [Route("api/file-management/files")] public?class?FileController?:?FileManagementController {protected?IFileAppService?FileAppService?{?get;?}public?FileController(IFileAppService?fileAppService){FileAppService?=?fileAppService;}[HttpGet][Route("{blobName}")]public?virtual?async?Task<FileResult>?GetAsync(string?blobName){var?fileDto?=?await?FileAppService.FindByBlobNameAsync(blobName);return?File(fileDto.Bytes,?MimeTypes.GetByExtension(Path.GetExtension(fileDto.FileName)));}[HttpPost][Route("upload")][Authorize]public?virtual?async?Task<JsonResult>?CreateAsync(IFormFile?file){if?(file?==?null){throw?new?UserFriendlyException("No?file?found!");}var?bytes?=?await?file.GetAllBytesAsync();var?result?=?await?FileAppService.CreateAsync(new?FileDto(){Bytes?=?bytes,FileName?=?file.FileName});return?Json(result);} }

單元測試

針對以上內容做一個簡單的測試,首先為Blob系統配置一個提供程序。

我這里使用最簡單的文件系統來儲存,所以需要安裝Volo.Abp.BlobStoring.FileSystem。在Application.Tests項目目錄下執行:abp add-package Volo.Abp.BlobStoring.FileSystem

配置默認容器

\modules\file-management\test\Xhznl.FileManagement.Application.Tests\FileManagementApplicationTestModule.cs:

[DependsOn(typeof(FileManagementApplicationModule),typeof(FileManagementDomainTestModule),typeof(AbpBlobStoringFileSystemModule))] public?class?FileManagementApplicationTestModule?:?AbpModule {public?override?void?ConfigureServices(ServiceConfigurationContext?context){Configure<AbpBlobStoringOptions>(options?=>{options.Containers.ConfigureDefault(container?=>{container.UseFileSystem(fileSystem?=>{fileSystem.BasePath?=?"D:\\my-files";});});});base.ConfigureServices(context);} }

測試用例

\modules\file-management\test\Xhznl.FileManagement.Application.Tests\Files\FileAppService_Tests.cs:

public?class?FileAppService_Tests?:?FileManagementApplicationTestBase {private?readonly?IFileAppService?_fileAppService;public?FileAppService_Tests(){_fileAppService?=?GetRequiredService<IFileAppService>();}[Fact]public?async?Task?Create_FindByBlobName_Test(){var?blobName?=?await?_fileAppService.CreateAsync(new?FileDto(){FileName?=?"微信圖片_20200813165555.jpg",Bytes?=?await?System.IO.File.ReadAllBytesAsync(@"D:\WorkSpace\WorkFiles\雜項\圖片\微信圖片_20200813165555.jpg")});blobName.ShouldNotBeEmpty();var?fileDto?=?await?_fileAppService.FindByBlobNameAsync(blobName);fileDto.ShouldNotBeNull();fileDto.FileName.ShouldBe("微信圖片_20200813165555.jpg");} }

運行測試

測試通過,blob也已經存入D:\my-files:

模塊引用

下面回到主項目,前面的章節中已經介紹過,模塊的引用依賴都已經添加完成,下面就直接從數據庫遷移開始。

\src\Xhznl.HelloAbp.EntityFrameworkCore.DbMigrations\EntityFrameworkCore\HelloAbpMigrationsDbContext.cs:

public?class?HelloAbpMigrationsDbContext?:?AbpDbContext<HelloAbpMigrationsDbContext> {public?HelloAbpMigrationsDbContext(DbContextOptions<HelloAbpMigrationsDbContext>?options):?base(options){}protected?override?void?OnModelCreating(ModelBuilder?builder){......builder.ConfigureFileManagement();......} }

打開程序包管理器控制臺,執行以下命令:

Add-Migration "Added_FileManagement"

Update-Database

此時數據庫已經生成了File表:

還有記得在HttpApi.Host項目配置你想要的blob提供程序。

最后結合前端測試一下吧:

最后

以上就是本人所理解的abp模塊開發一個相對完整的流程,還有些概念后面再做補充。因為這個例子比較簡單,文中有些環節是不必要的,需要結合實際情況去取舍。代碼地址:https://github.com/xiajingren/HelloAbp

參考資料

[1]

BLOB 存儲: https://docs.abp.io/zh-Hans/abp/latest/Blob-Storing

[2]

自動API控制器: https://docs.abp.io/zh-Hans/abp/latest/API/Auto-API-Controllers

如果本文對您有用,

不妨點個“”或者轉發朋友圈支持一下

總結

以上是生活随笔為你收集整理的初识ABP vNext(11):聚合根、仓储、领域服务、应用服务、Blob储存的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。