一、ABP學習文檔


ABP的由來

從零開始創建一個企業應用程序是一件繁瑣的事,因爲需要重複做很多常見的基礎工作。許多公司都在開發自己的應用程序框架來重用於不同的項目,然後在框架的基礎上開發一些新的功能。但並不是每個公司都有這樣的實力。ABP因此誕生,作者之所以把項目命名爲“ASP.NET Boilerplate”,就是希望它能成爲開發一般企業WEB應用的新起點,直接把ABP作爲項目模板。

一、什麼是ABP

ABP是爲新的現代Web應用程序使用最佳實踐和使用最流行工具的一個起點。可作爲一般用途的應用程序的基礎框架或項目模板。ABP 提供了一個應用程序開發模型用於最佳實踐。它擁有基礎類、接口和工具使我們容易建立起可維護的大規模的應用程序。

二、ABP具有什麼的功能

  • 依賴注入:ABP使用並提供一個強大而且符合約定的DI框架。上述的應用服務,按照約定臨時的(每個請求Request創建一個)註冊到DI容器,它能簡單地注入所有依賴項(如示例中的Irepository)。
  • 倉儲:ABP能爲每個實體創建一個默認的倉儲(如示例中的Irepository)。默認倉儲包含許多有用的方法,如示例中的FirstOrDefault方法。我們可以根據需要,很容易地擴展默認倉儲。倉儲抽象了DBMS和ORM以及簡化了數據訪問邏輯。
  • 授權:ABP可以檢查許可。如果當前用戶沒有“updating
    task”權限或是未登錄,ABP就會阻止他們訪問UpdateTask方法。用陳述性的特性來簡化授權,當然還有另外的授權方式。
  • 驗證:ABP自動檢查input是否爲null。根據標準的數據註釋特性和自定義驗證規則,檢查一個input的所有屬性。如果請求沒有通過驗證,會拋出一個對應的驗證異常。
  • 審計日誌:根據約定和配置,每個請求的用戶、瀏覽器、Ip地址、調用服務、方法、參數、調用時間、執行耗時和其它的一些信息會被自動地保存下來。
  • 工作單元:在ABP裏,每個應用服務方法都默認地被認定爲一個工作單元。在方法開始前,它自動創建一個連接並開啓一個事務。如果方法成功完成,接着事務會被提交併釋放連接。即使是使用不同的倉儲或是方法,它們都可以是原子性(事務性)的,並且當事務提交時實體中所有的修改都自動地被保存。因此,如同示例所示,我們甚至不需要去調用_repository.Update(task)方法。
  • 異常處理:我們幾乎不用在一個使用ABP的Web應用中寫異常處理。所有的異常都自動地被默認處理。當一個異常發生,ABP自動記錄它並返回一個對應的結果給客戶端。例如,一個AJAX請求,它會返回一個Json對象給客戶端,告知發生了一個錯誤。如示例所示,UserFriendlyException可以向客戶端隱藏具體的異常,顯示友好信息。它同樣可以在客戶端理解並處理客戶端錯誤,並向用戶顯示對應的信息。
  • 日誌:如你所見,我們可以用定義在基類中的Logger對象寫日誌。默認使用Log4Net,不過這是可修改和可配置的。
  • 本地化:請注意我們在拋出異常時,使用了L方法。因此,它可自動依據用戶區域,使用相應的本地化信息。當然,我們需要在某處定義CouldNotFoundTheTaskMessage(更多信息參見“本地化”文檔)。
  • 自動映射:最後一行代碼,我們使用ABP的MapTo擴展方法來映射input屬性到實體屬性。它使用AutoMapper庫來執行映射。因此,我們可以簡單地基於命名約定,從一個對象映射到另一個。
  • 動態Web API 層:實際上TaskAppService是一個簡單的類(甚至是不需要從ApplicationService繼承)。我們通常包裝一個Web API 控制器爲Javascript客戶端公開方法,ABP會在運行時自動地完成這件事。因此,我們可以直接在客戶端使用應用服務。
  • 動態Javascript AJAX 代理:ABP創建Javascript代理方法,以便就本地調用一樣,來調用應用服務。

三、如何搭建啓動一個ABP項目

  1. 去官網下載一個ABP項目,並填寫你的項目名。https://aspnetboilerplate.com/Templates
    在這裏插入圖片描述

  2. 解壓zip文件,用visual studio打開解決方案。並修改Web.Host項目下的appsetting.json文件,配置數據庫連接字符串。
    在這裏插入圖片描述

  3. 設置EntityFrameworkCore項目爲啓動項目,並打開程序包管理控制檯
    在這裏插入圖片描述

輸入命令:Add-Migration,會看到在這個項目下會生成好多個文件
在這裏插入圖片描述
在這裏插入圖片描述

再執行命令:Update-Database
在這裏插入圖片描述

命令執行完後會自動生成一個新的數據庫。
在這裏插入圖片描述
把Web.Host設置爲啓動項目,並啓動程序。
在這裏插入圖片描述

  1. 啓動前端Vue項目,用visual studio code打開Vue項目
    在這裏插入圖片描述

打開一個新的TERMINAL
在這裏插入圖片描述
輸入命令:npm install ,安裝項目所依賴的包(第一次安裝需要較長的時間,請耐心等候)。
在這裏插入圖片描述
所有依賴包都安裝完成後,執行命令:npm run serve,啓動項目(賬號:admin,密碼:123qwe)。
在這裏插入圖片描述
在這裏插入圖片描述

四、如何添加一個簡單的功能

  1. 在Core項目下定義一個APJUser類:
public class APJUser : Entity<int>
    {
        [Column("Id")]
        public override int Id { get; set; }

        public string Name { get; set; }

        public string Gender { get; set; }

        public string Email { get; set; }
    }
  1. 在EntityFrameworkCore項目下,找到DbContext,並添加以下代碼:
 public DbSet<APJUser> APJUsers { get; set; }
  1. 執行命令:Add-Migration(注意:要將EntityFrameworkCore設置爲啓動項目)
    在這裏插入圖片描述
    再執行命令:Update-Database
    在這裏插入圖片描述
    會看到在數據庫中會多了APJUser這麼一張表:
    在這裏插入圖片描述

我們往表中插入幾條數據,方便我們測試:

INSERT INTO [dbo].[APJUsers]
([Name],[Gender],[Email])
VALUES
('Tim','男','[email protected]'),
('Jimmy','男','[email protected]'),
('Lily','女','[email protected]'),
('Jenny','女','[email protected]')
  1. 在項目Application中,創建以下幾個類:
    在這裏插入圖片描述
    [AutoMapFrom(typeof(APJUser))]
    public class APJUserDto: EntityDto
    {
        public string Name { get; set; }

        public string Gender { get; set; }

        public string Email { get; set; }

    }

    [AutoMapTo(typeof(APJUser))]
    public class CreateAPJUserDto
    {
        public string Name { get; set; }

        public string Gender { get; set; }

        public string Email { get; set; }
    }

    public class PagedAPJUserResultRequestDto : PagedResultRequestDto
    {
        public string Keyword { get; set; }
        public bool? IsActive { get; set; }
    }

    public interface IAPJUserAppService : IAsyncCrudAppService<APJUserDto, int, PagedAPJUserResultRequestDto, CreateAPJUserDto, APJUserDto>
    {
    }

    public class APJUserAppService : AsyncCrudAppService<APJUser, APJUserDto, int, PagedAPJUserResultRequestDto, CreateAPJUserDto, APJUserDto>, IAPJUserAppService
    {
        private IRepository<APJUser, int> _repository;

        public APJUserAppService(IRepository<APJUser, int> repository) : base(repository)
        {
            _repository = repository;
        }
    }

然後啓動項目,看一下預期效果:
在這裏插入圖片描述
ABP會幫助我們自動生成相應的API,實現CRUD的功能,下面我們來調用一下,發現有幾個問題。
問題一:GetAll()方法中,KeyWord參數設置無效。

修改方法,在APJUserAppService重寫一下CreateFilteredQuery()的方法
protected override IQueryable CreateFilteredQuery(PagedAPJUserResultRequestDto input)
{
return _repository.GetAll().WhereIf(!string.IsNullOrWhiteSpace(input.Keyword), t => t.Name.Contains(input.Keyword));
}

問題二:Update()方法報錯。

修改方法
protected override void MapToEntity(APJUserDto updateInput, APJUser entity)
{
entity.Name = updateInput.Name;
entity.Gender = updateInput.Gender;
entity.Email = updateInput.Email;
}

至此,一個簡單的CURD功能添加完成。
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

五、ABP如何分配權限

在Core項目下,找到PermissionNames.cs這個文件:
在這裏插入圖片描述
定義一個PermissionName:

 public const string Pages_APJUser_GetAll = "Pages.APJUser.GetAll";

找到Core項目下的AuthorizationProvider.cs文件,並添加一個權限:

context.CreatePermission(PermissionNames.Pages_APJUser_GetAll, L("APJ_User查詢權限"));//第二個參數爲多資源參數

方法一:
回到APJUserAppService.cs,修改一下查詢的方法,在GetAll的方法上添加一個標籤:

[AbpAuthorize(PermissionNames.Pages_APJUser_GetAll)]
public override Task<PagedResultDto<APJUserDto>> GetAll(PagedAPJUserResultRequestDto input)
{
    return base.GetAll(input);
}

這時,重新編譯整個解決方案,並啓動項目。由於admin賬號,默認是啓動所有的權限,所以我們需要先將admin賬號的Pages_APJUser_GetAll權限去掉纔可以測試。在Role界面,將Pages_APJUser_GetAll權限去掉。
在這裏插入圖片描述
這時再調用這個API,則會提示沒有權限:
在這裏插入圖片描述
方法二:
調用PermissionChecker.Authorize()方法

 //[AbpAuthorize(PermissionNames.Pages_APJUser_GetAll)]
public override Task<PagedResultDto<APJUserDto>> GetAll(PagedAPJUserResultRequestDto input)
{
    PermissionChecker.Authorize(PermissionNames.Pages_APJUser_GetAll);       
    return base.GetAll(input);
}

在這裏插入圖片描述
方法三:
重寫CheckGetAllPermission()方法,我們可以看到,ABP默認幫我們實現了很多方法。其中,部分方法是virtual方法,是可以重寫的:
在這裏插入圖片描述
接下來我們重寫一下CheckGetAllPermission()方法:

protected override void CheckGetAllPermission()
{
      //業務邏輯
      throw new AbpAuthorizationException("對不起,你沒有這個權限");
}

然後,再GetAll()方法中調用。

//[AbpAuthorize(PermissionNames.Pages_APJUser_GetAll)]
public override Task<PagedResultDto<APJUserDto>> GetAll(PagedAPJUserResultRequestDto input)
{
     //PermissionChecker.Authorize(PermissionNames.Pages_APJUser_GetAll);
     CheckGetAllPermission();
     return base.GetAll(input);
}

六、本地資源化

  1. 在Core項目下找到Localization\SourceFiles\APJ.xml
    在這裏插入圖片描述
  2. 添加一個新的資源:
<text name="TestResource1">This is a test.</text>
  1. 實現:
    方法一:
    在ApplicationService層,注入ILocalizationManager
private ILocalizationManager _localizationManager;

public APJUserAppService(ILocalizationManager localizationManager) : base(repository)
{
      _repository = repository;
      _localizationManager = localizationManager;
}

定義一個接口方法,並實現它:

string GetLozationString(string key, string language);

public string GetLozationString(string key, string language = "en")
{
     return _localizationManager.GetString(APJConsts.LocalizationSourceName, key, new CultureInfo(language));
}
  1. 調用結果:
    在這裏插入圖片描述

方法二:
再構造函數中初始化 LocalizationSourceName,

public APJUserAppService(IRepository<APJUser, int> repository, ILocalizationManager localizationManager) : base(repository)
{
       _repository = repository;
       _localizationManager = localizationManager;
       LocalizationSourceName = APJConsts.LocalizationSourceName;
}

修改獲取多資源的方法:

 public string GetLozationString(string key = "HomePage", string language = "zh-HK")
{
     //return _localizationManager.GetString(APJConsts.LocalizationSourceName, key, new CultureInfo(language));

     return L(key, new CultureInfo(language,false));
}

在這裏插入圖片描述

七、記錄日誌

  1. 通過依賴注入,注入Logger對象(注意:僅僅能使用public屬性):
  public ILogger Logger { get; set; }

  public APJUserAppService(IRepository<APJUser, int> repository, ILocalizationManager localizationManager) : base(repository)
{
     _repository = repository; 
     _localizationManager = localizationManager;
     LocalizationSourceName = APJConsts.LocalizationSourceName;
     Logger = NullLogger.Instance;
}

  1. 調用:
  Logger.Info("this is a test");

  Logger.Debug("this is debug test");

  Logger.Warn("this is warm test");

得到的結果:(放在Logs.txt文件中)

INFO 2019-10-12 12:05:01,346 [6 ] APJ.APJManagement.APJUserAppService - this is a test
DEBUG 2019-10-12 12:05:01,346 [6 ] APJ.APJManagement.APJUserAppService - this is debug test
WARN 2019-10-12 12:05:01,346 [6 ] APJ.APJManagement.APJUserAppService - this is warm test

  1. 配置log4
    找到Web.Host項目下的log4net.config文件,並打開:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
  <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender" >
    <file value="App_Data/Logs/Logs.txt" />
    <appendToFile value="true" />
    <rollingStyle value="Size" />
    <maxSizeRollBackups value="10" />
    <maximumFileSize value="10000KB" />
    <staticLogFileName value="true" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%-5level %date [%-5.5thread] %-40.40logger - %message%newline" />
    </layout>
  </appender>
  <root>
    <appender-ref ref="RollingFileAppender" />
    <level value="DEBUG" />
  </root>
</log4net>

詳細的配置請參考文章:
https://blog.csdn.net/u013160017/article/details/81392154
https://blog.csdn.net/eagleuniversityeye/article/details/80582140

八、數據驗證

方法一:
使用C#自定義標籤,如[Required]

[Required]
public string Name { get; set; } 

方法二:
自定義數據驗證
實現接口ICustomValidate

    public class CreateAPJUserDto:ICustomValidate
    {
        [Required]
        public string Name { get; set; }

        public string Gender { get; set; }

        public string Email { get; set; }

        public void AddValidationErrors(CustomValidationContext context)
        {
            if (Name.Length>10)
            {
                context.Results.Add(new ValidationResult("Name長度不能大於10"));
            }
        }
    }

結果:
在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章