初識ABP vNext(9):ABP模塊化開發

Tips:本篇已加入系列文章閱讀目錄,可點擊查看更多相關文章。html

目錄數據庫

  • 前言
  • 開始
    • 建立模塊
    • 模塊開發
      • 應用服務
      • 運行模塊
      • 單元測試
    • 模塊使用
  • 最後

前言

在以前的章節中介紹過ABP擴展實體,當時在用戶表擴展了用戶頭像字段,用戶頭像就涉及到文件上傳和文件存儲。文件上傳是不少系統都會涉及到的一個基礎功能,在ABP的模塊化思路下,文件管理能夠作成一個通用的模塊,便於之後在多個項目中複用。單純實現一個文件上傳的功能並不複雜,本文就藉着這個簡單的功能來介紹一下ABP模塊化開發的最基本步驟。api

開始

建立模塊

首先使用ABP CLI建立一個模塊:abp new Xhznl.FileManagement -t module --no-ui服務器

建立完成後會獲得以下文件:async

在主項目中添加對應模塊的引用,Application=>Application,Domain=>Domain,HttpApi=>HttpApi 等等。例如:ide

須要添加引用的項目:Application、Application.Contracts、Domain、Domain.Shared、EntityFrameworkCore、HttpApi、HttpApi.Client模塊化

手動添加這些引用比較麻煩,你能夠搭建本身的私有NuGet服務器,把模塊的包發佈到私有NuGet上,而後經過NuGet來安裝引用。兩種方式各有優缺點,具體請參考自定義現有模塊,關於私有NuGet搭建能夠參考:十分鐘搭建本身的私有NuGet服務器-BaGet。post

而後給這些項目的模塊類添加對應的依賴,例如:單元測試

經過上面的方式引用模塊,使用visual studio是沒法編譯經過的:測試

須要在解決方案目錄下,手動執行dotnet restore命令便可:

模塊開發

接下來關於文件管理功能的開發,都在模塊Xhznl.FileManagement中進行,它是一個獨立的解決方案。初學ABP,下面就以儘可能簡單的方式來實現這個模塊。

應用服務

模塊開發一般從Domain層實體創建開始,可是這裏先跳過。先在FileManagement.Application.Contracts項目添加應用服務接口和Dto。

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

public interface IFileAppService : IApplicationService{ Task<byte[]> GetAsync(string name); Task<string> CreateAsync(FileUploadInputDto input);}

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

public class FileUploadInputDto{ [Required] public byte[] Bytes { get; set; } [Required] public string Name { get; set; }}

而後是FileManagement.Application項目,實現應用服務,先定義一個配置類。

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

public class FileOptions{ /// <summary> /// 文件上傳目錄 /// </summary> public string FileUploadLocalFolder { get; set; } /// <summary> /// 容許的文件最大大小 /// </summary> public long MaxFileSize { get; set; } = 1048576;//1MB /// <summary> /// 容許的文件類型 /// </summary> public string[] AllowedUploadFormats { get; set; } = { ".jpg", ".jpeg", ".png", "gif", ".txt" };}

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

public class FileAppService : FileManagementAppService, IFileAppService{ private readonly FileOptions _fileOptions; public FileAppService(IOptions<FileOptions> fileOptions) {  _fileOptions = fileOptions.Value; } public Task<byte[]> GetAsync(string name) {  Check.NotNullOrWhiteSpace(name, nameof(name));  var filePath = Path.Combine(_fileOptions.FileUploadLocalFolder, name);  if (File.Exists(filePath))  {   return Task.FromResult(File.ReadAllBytes(filePath));  }  return Task.FromResult(new byte[0]); } [Authorize] public Task<string> CreateAsync(FileUploadInputDto 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"})    });  }  if (input.Bytes.Length > _fileOptions.MaxFileSize)  {   throw new UserFriendlyException($"File exceeds the maximum upload size ({_fileOptions.MaxFileSize / 1024 / 1024} MB)!");  }  if (!_fileOptions.AllowedUploadFormats.Contains(Path.GetExtension(input.Name)))  {   throw new UserFriendlyException("Not a valid file format!");  }  var fileName = Guid.NewGuid().ToString("N") + Path.GetExtension(input.Name);  var filePath = Path.Combine(_fileOptions.FileUploadLocalFolder, fileName);  if (!Directory.Exists(_fileOptions.FileUploadLocalFolder))  {   Directory.CreateDirectory(_fileOptions.FileUploadLocalFolder);  }  File.WriteAllBytes(filePath, input.Bytes);  return Task.FromResult("/api/file-management/files/" + fileName); }}

服務實現很簡單,就是基於本地文件系統的讀寫操做。

下面是FileManagement.HttpApi項目,添加控制器,暴露服務API接口。

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

[RemoteService][Route("api/file-management/files")]public class FileController : FileManagementController{ private readonly IFileAppService _fileAppService; public FileController(IFileAppService fileAppService) {  _fileAppService = fileAppService; } [HttpGet] [Route("{name}")] public async Task<FileResult> GetAsync(string name) {  var bytes = await _fileAppService.GetAsync(name);  return File(bytes, MimeTypes.GetByExtension(Path.GetExtension(name))); } [HttpPost] [Route("upload")] [Authorize] public 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 FileUploadInputDto()  {   Bytes = bytes,   Name = file.FileName  });  return Json(result); }}

運行模塊

ABP的模板是能夠獨立運行的,在FileManagement.HttpApi.Host項目的模塊類FileManagementHttpApiHostModule配置FileOptions:

修改FileManagement.HttpApi.Host和FileManagement.IdentityServer項目的數據庫鏈接配置,而後啓動這2個項目,不出意外的話能夠看到以下界面。

FileManagement.HttpApi.Host:

FileManagement.IdentityServer:

如今你可使用postman來測試一下File的2個API,固然也能夠編寫單元測試。

單元測試

更好的方法是編寫單元測試,關於如何作好單元測試能夠參考ABP源碼,下面只作一個簡單示例:

模塊使用

模塊測試經過後,回到主項目。模塊引用,模塊依賴前面都已經作好了,如今只需配置一下FileOptions,就可使用了。

目前FileManagement.Domain、FileManagement.Domain.Shared、FileManagement.EntityFrameworkCore這幾個項目暫時沒用到,項目結構也不是固定的,能夠根據本身實際狀況來調整。

最後

本文的模塊示例比較簡單,只是完成了一個文件上傳和顯示的基本功能,關於實體,數據庫,領域服務,倉儲之類的都暫時沒用到。可是相信能夠經過這個簡單的例子,感覺到ABP插件式的開發體驗,這是一個好的開始,更多詳細內容後面再作介紹。本文參考了ABP blogging模塊的文件管理,關於文件存儲,ABP中也有一個BLOB系統能夠了解一下。

初識ABP vNext(9):ABP模塊化開發 文章轉載:http://www.shaoqun.com/a/472296.html
相關文章
相關標籤/搜索