X-Admin&ABP框架開發-版本管理

  • 2020 年 4 月 12 日
  • 筆記

  多租戶系統中,針對於不同租戶開放不同功能,或是按照不同功能進行收費管理,需要從宿主本身去管理租戶的版本資訊,如同酒店人員對不同房間收取不同費用,依據房間內部設施,房間大小等設置不同收費標準。Abp系統中默認是多租戶的,並且在Zero模組中實現了版本管理功能。 

   演示地址:http://119.3.138.127/,更改Account/HostLogin進入宿主管理

 

一、設計前提

  基於Abp進行了相關限制,我將多租戶變成了單租戶,不允許添加新的租戶,由於日常接觸中,發現除了雲平台這種SaaS需要多租戶,對於企業客戶來講,自備物理伺服器或自購雲伺服器是常有的事情,因此對於該部分客戶而言,多租戶也就沒有太多意義,但是從軟體公司本身考慮,一套軟體能夠銷售多家客戶,能夠通過簡單配置,開放關閉某些功能,以此來適應客戶功能需求,是最佳選項了。因此對於這兩種情況考慮後,對於本系統而言,採用的是單租戶+宿主形式的,企業客戶使用單租戶,宿主形式留給軟體公司方便配置單租戶實際需要的功能。

  在Zero中,已經默認實現了版本管理,但是對於非收費版本的頁面管理,應用服務等沒有具體程式碼實現。

 

二、版本管理

1、應用層增加版本應用服務,對於版本需要進行的用戶操作歸納為三個。

  • 可查看現有版本列表;
  • 可對現有版本資訊及版本擁有的功能項進行編輯更改;
  • 可增加或是刪除版本;
/// <summary>  /// 版本管理應用服務介面  /// </summary>  public interface IEditionAppService : IApplicationService  {      /// <summary>      /// 獲取全部版本列表      /// </summary>      /// <returns></returns>      Task<ListResultDto<EditionListDto>> GetEditionsList();        /// <summary>      /// 獲取版本用於編輯      /// </summary>      /// <param name="input"></param>      /// <returns></returns>      Task<GetEditionForEditOutput> GetEditionForEdit(NullableIdDto input);        /// <summary>      /// 創建或更新版本      /// </summary>      /// <param name="input"></param>      /// <returns></returns>      Task CreateOrUpdateEdition(CreateOrUpdateEditionInput input);        /// <summary>      /// 刪除版本      /// </summary>      /// <param name="input"></param>      /// <returns></returns>      Task DeleteEdition(EntityDto input);        /// <summary>      /// 租戶更換版本      /// </summary>      /// <param name="input"></param>      /// <returns></returns>      Task MoveTenantsToAnotherEdition(MoveTenantsToAnotherEditionDto input);  }

2、實現應用服務

實現版本應用服務介面,以創建版本為例,頂部許可權驗證,增加版本資訊,並且設置該版本所擁有的功能項,對於版本領域服務,Zero模組提供了完整實現AbpEditionManager,只需調用即可。

[AbpAuthorize(PermissionNames.Pages_Frame_Editions_Create)]  private async Task CreateEdition(CreateOrUpdateEditionInput input)  {      var edition = ObjectMapper.Map<Edition>(input.Edition);        await _editionManager.CreateAsync(edition);      await CurrentUnitOfWork.SaveChangesAsync();        await SetFeatureValues(edition, input.FeatureValues);  }    private Task SetFeatureValues(Edition edition, List<NameValueDto> featureValues)  {      return _editionManager.SetFeatureValuesAsync(edition.Id, featureValues.Select(fv => new NameValue(fv.Name, fv.Value)).ToArray());  }

3、控制器中增加版本管理控制器並設計相應的方法(逐漸認識到,能夠使用Dto的盡量使用Dto),控制器部分主要承擔路由功能,將前端請求轉發到應用服務、領域服務中。

 4、頁面層實現,列表展示+彈框添加/編輯,彈框內展示出功能項樹結構,供版本配置需要的功能項。

 5、頁面功能展示,列表展示現有版本,因考慮到版本數量不會很多,無需分頁也無需條件查詢。該部分菜單僅對宿主提供

 

三、版本功能管理

   對於功能項,ABP框架中採用聲明式,現在領域層中聲明具體的功能項,在程式碼中,依照當前租戶是否存在聲明的某個功能項去決定是否執行某個功能,

1、功能項聲明,在Core層->Features文件夾中聲明該系統擁有的功能,需要對租戶進行控制劃分的。如客戶服務模組,對於小部分企業客戶而言,可能不需要該模組,則可通過對客戶服務模組進行功能控制,頁面上,程式碼中該部分功能都會繞過去。

/// <summary>  /// 功能管理  /// </summary>  public static class AppFeatures  {      public const string HostSettings = "App.HostSettings";        public const string CustomerService = "App.CustomerService";  }

2、功能綁定到系統中,在Features文件夾中,AppFeatureProvider負責將聲明的功能綁定到系統中,可以對功能項進行默認設置,如對於客戶服務要默認為都具有,可以更改defaultValue設置為true,具體更豐富的設計查看Abp提供的重載方法。可對功能項進行樹結構設計。

/// <summary>  /// 功能設置提供器  /// </summary>  public class AppFeatureProvider : FeatureProvider  {      public override void SetFeatures(IFeatureDefinitionContext context)      {          var hostSettings = context.Create(              AppFeatures.HostSettings,              defaultValue: "false",              displayName: L("HostSettings"),              inputType: new CheckboxInputType()          );            var customerService = context.Create(              AppFeatures.CustomerService,              defaultValue: "false",              displayName: L("CustomerService"),              inputType: new CheckboxInputType()          );            var customerServiceMaps = customerService.CreateChildFeature(              AppFeatures.CustomerService_Maps,              defaultValue: "false",              displayName: L("CustomerServiceMaps"),              inputType: new CheckboxInputType()          );      }        private ILocalizableString L(string name)      {          return new LocalizableString(name, SurroundConsts.LocalizationSourceName);      }  }

3、版本管理中關聯功能項,在版本管理頁面,編輯版本資訊彈框內右側tab頁功能項樹結構,可查看系統已有功能,並通過勾選形式確定該版本需要的功能。

 

四、租戶版本管理

  軟體公司可以在發售給客戶的軟體中預先配置好幾個版本,方便部署實施時,更改租戶使用的版本即可完成功能劃分。默認使用的是單個租戶,因此,對於租戶的增刪操作直接pass掉了。對於Abp提供的多租戶的管理部分程式碼進行相關更改,適應單租戶的一些操作。

  • 可查看當前租戶資訊;
  • 可切換租戶使用版本;

1、在已有租戶應用服務中更改已有程式碼,取消原有繼承的CRUD服務,實現獲取租戶列表,更改版本等幾個操作。

/// <summary>  /// 租戶應用服務  /// </summary>  public interface ITenantAppService : IApplicationService  {      /// <summary>      /// 獲取單個租戶      /// </summary>      /// <param name="input"></param>      /// <returns></returns>      Task<TenantListDto> GetTenant(EntityDto<int> input);        /// <summary>      /// 獲取全部租戶列表      /// </summary>      /// <returns></returns>      Task<ListResultDto<TenantListDto>> GetTenantsList();        /// <summary>      /// 移動當前租戶版本到其它版本      /// </summary>      /// <param name="input"></param>      /// <returns></returns>      Task MoveTenantToAnotherEdition(MoveTenantToAnotherEditionInput input);  }

2、實現替換的幾個租戶應用服務介面方法,此處僅展示切換租戶版本。完成頂部許可權驗證,版本參數驗證,租戶版本修改。

[AbpAuthorize(PermissionNames.Pages_Frame_Tenants_MoveTenantToAnotherEdition)]  public async Task MoveTenantToAnotherEdition(MoveTenantToAnotherEditionInput input)  {      if (input.SourceEditionId == input.TargetEditionId)      {          throw new UserFriendlyException("原版本與目標版本一致,無需切換");      }        var tenant = await _tenantManager.GetByIdAsync(input.TenantId);      tenant.EditionId = input.TargetEditionId;      await _tenantManager.UpdateAsync(tenant);  }

 3、租戶控制器層面已經存在了相關程式碼,改造部分程式碼並完成頁面實現,頁面實現中主要是彈框內列舉出當前系統已有的版本列表資訊,方便切換版本。

 4、頁面效果實現,版本切換操作實現。

 

五、菜單許可權控制

  對於諸如版本管理、租戶管理這部分菜單僅能夠對宿主進行開放,因此在許可權列表中對該部分許可權進行控制,在導航菜單中會依據是否有許可權進行過濾菜單。許可權中使用命名參數multiTenancySides設置為僅宿主使用。

#region 版本管理  var editions = frame.CreateChildPermission(PermissionNames.Pages_Frame_Editions, L("Editions"), multiTenancySides: MultiTenancySides.Host);  editions.CreateChildPermission(PermissionNames.Pages_Frame_Editions_Create, L("CreateEdition"), multiTenancySides: MultiTenancySides.Host);  editions.CreateChildPermission(PermissionNames.Pages_Frame_Editions_Update, L("UpdateEdition"), multiTenancySides: MultiTenancySides.Host);  editions.CreateChildPermission(PermissionNames.Pages_Frame_Editions_Delete, L("DeleteEdition"), multiTenancySides: MultiTenancySides.Host);  editions.CreateChildPermission(PermissionNames.Pages_Frame_Editions_MoveTenantsToAnotherEdition, L("MoveTenantsToAnotherEdition"), multiTenancySides: MultiTenancySides.Host);  #endregion    #region 租戶管理  var tenants = frame.CreateChildPermission(PermissionNames.Pages_Frame_Tenants, L("Tenants"), multiTenancySides: MultiTenancySides.Host);  tenants.CreateChildPermission(PermissionNames.Pages_Frame_Tenants_MoveTenantToAnotherEdition, L("MoveTenantsToAnotherEdition"), multiTenancySides: MultiTenancySides.Host);  #endregion

  對於宿主登錄,在主頁面設置了兩個入口,如登錄時使用Account/HostLogin則為宿主登錄,否則為租戶登錄。

 

 倉庫地址:https://gitee.com/530521314/Partner.Surround.git 

2020-04-12,望技術有成後能回來看見自己的腳步