返回总目录


本篇目录

介绍###

大多数的Saas(多租户)应用都有不同 功能版本(包)。因此,他们可以给租户(客户)提供不同的 价格和功能选项

ABP提供了功能系统使得这个更简单。我们可以 定义功能,然后检查某个功能是否对一个租户 开启了,最后将功能系统 集成到其他的ABP概念中(如权限和菜单)。

关于IFeatureValueStore

功能系统使用了IFeatureValueStore来获得功能的值。虽然你可以用自己的方式实现该接口,但是它已经完全实现在了 module-zero项目中。如果没有实现该接口,那么默认会使用NullFeatureValueStore对所有的功能返回null(此时使用默认的功能值)。

功能类型###

有两种基本功能类型。

布尔功能

可以是"true"或"false"。这种类型的功能(对于一个版本或者一个租户)可能是开启的或者 关闭的

值功能

可以是任意值。虽然它是以字符串存储和检索的,但是数值也可以轻松地存储为字符串。

比如,我们的应用程序可能是一个任务管理应用,我们可能在一个月内对于创建任务会有限制。假如说我们有两个不同的版本:一个版本每个月允许创建1000个任务,但是另一个每个月允许创建5000个任务。因此,这个功能应该存储为值,而不是简单的true或false。

定义功能###

在检查功能之前应该先定义功能。一个模块可以通过从FeatureProvider类派生来定义自己的功能。这里有一个定义了3个功能的非常简单的功能提供者:

public class AppFeatureProvider : FeatureProvider
{
public override void SetFeatures(IFeatureDefinitionContext context)
{
var sampleBooleanFeature = context.Create("SampleBooleanFeature", defaultValue: "false");
sampleBooleanFeature.CreateChildFeature("SampleNumericFeature", defaultValue: "10");
context.Create("SampleSelectionFeature", defaultValue: "B");
}
}

创建功能提供者之后,我们应该在模块的PreInitialize方法中注册,如下所示:

Configuration.Features.Providers.Add<AppFeatureProvider>();

基本功能属性

一个功能的定义至少要求两个属性:

  • Name:识别该功能唯一的名字(字符串)。
  • DefaultValue:默认值。当我们需要该功能的值时会用到该属性,而且对于当前的租户不可用。

上面的代码样例中,我们定义了一个名为"SampleBooleanFeature"布尔功能,它的默认值是"false"(不可用)。我们也定义了两个值功能(SampleNumericFeature定义为SampleBooleanFeature的孩子)。

提示:为功能名称创建一个常量字符串,然后在任何地方使用时会防止拼写失误。

其他功能属性

虽然对于ABP来说一个唯一的名称和默认值属性已经足够了,但是对于细节的控制还有许多其他的功能属性。

  • Scope:FeatureScope枚举值之一。它可以是Edition(如果只为版本级别设置该功能), Tenant(如果只为租户级别设置该功能),或者 All(如果为版本和租户都可以设置该功能,这种情况下,租户的设置会覆盖版本的设置)。默认值是All。
  • DisplayName:给用户显示该功能名称的本地化字符串。
  • Description:给用户显示该功能细节描述的本地化字符串。
  • InputType:该功能的UI输入类型。
  • Attributes:任意的自定义键值对字典,可以和该功能关联起来。

让我们看一下该功能的细节定义:

public class AppFeatureProvider : FeatureProvider
{
public override void SetFeatures(IFeatureDefinitionContext context)
{
var sampleBooleanFeature = context.Create(
AppFeatures.SampleBooleanFeature,
defaultValue: "false",
displayName: L("Sample boolean feature"),
inputType: new CheckboxInputType()
); sampleBooleanFeature.CreateChildFeature(
AppFeatures.SampleNumericFeature,
defaultValue: "10",
displayName: L("Sample numeric feature"),
inputType: new SingleLineStringInputType(new NumericValueValidator(1, 1000000))
); context.Create(
AppFeatures.SampleSelectionFeature,
defaultValue: "B",
displayName: L("Sample selection feature"),
inputType: new ComboboxInputType(
new StaticLocalizableComboboxItemSource(
new LocalizableComboboxItem("A", L("Selection A")),
new LocalizableComboboxItem("B", L("Selection B")),
new LocalizableComboboxItem("C", L("Selection C"))
)
)
);
} private static ILocalizableString L(string name)
{
return new LocalizableString(name, AbpZeroTemplateConsts.LocalizationSourceName);
}
}

注意:ABP没有使用这里的InputType。当为功能创建输入时,应用程序会使用它们。ABP只是提供了这些选项使得它更容易。

功能层次

正如样例功能提供者所示,一个功能可以有子功能。一个父母功能一般定义为 布尔功能。只有父母功能可用时,孩子功能才可用。ABP不强制这样做,但是建议这样做。

检查功能###

使用RequireFeature特性

我们可以为方法或类使用RequiredFeature特性,如下所示:

[RequiresFeature("ExportToExcel")]
public async Task<FileDto> GetReportToExcel(...)
{
...
}

该方法只有在"ExportToExcel"功能对当前租户开启时才会执行(当前租户从IAbpSession中获得)。如果没有开启该功能,那么就会自动抛出 AbpAuthorizationException

当然,RequiresFeature特性应该用于布尔类型功能。否则,你会得到异常。

RequiresFeature特性注意点

ABP对于功能检查使用了强大的动态方法拦截(interception)。因此,为方法使用RequiresFeature特性时有一些限制条件:

  • 不能用于私有方法。
  • 不能用于静态方法。
  • 不能用于非注入类的方法(我们必须使用DI)。

此外,

  • 如果该方法是通过一个接口(如应用服务通过接口调用)调用的,那么我们可以将它用于任何 public的方法。
  • 如果一个方法直接从类的引用调用(如MVC或Web API控制器),那么它应该是virtual的。
  • 如果一个方法是protected,那么该方法应该是 virtual

使用IFeatureChecker

我们可以注入并使用IFeatureChecker来手动检查一个功能(对于应用服务,MVC和Web API控制器,它会自动注入而且直接可以使用)。

IsEnabled

用于简单地检查给定的功能是否开启。例子:

public async Task<FileDto> GetReportToExcel(...)
{
if (await FeatureChecker.IsEnabledAsync("ExportToExcel"))
{
throw new AbpAuthorizationException("You don't have this feature: ExportToExcel");
} ...
}

IsEnabledAsync和其他方法都有同步版本。

当然,IsEnabled方法应该用于布尔类型功能。否则可能会抛异常。

如果你只想检查一个功能,然后抛出例子中的异常,那么你只需要使用CheckEnabled方法就行了。

GetValue

用于获得值类型功能的当前值,例子:

var createdTaskCountInThisMonth = GetCreatedTaskCountInThisMonth();
if (createdTaskCountInThisMonth >= FeatureChecker.GetValue("MaxTaskCreationLimitPerMonth").To<int>())
{
throw new AbpAuthorizationException("You exceed task creation limit for this month, sorry :(");
}

FeatureChecker方法也有对于特定租户的重载,不仅仅只对于当前的租户。

客户端

在客户端,我们使用abp.features命名空间来获得该功能的当前值。

isEnabled

var isEnabled = abp.features.isEnabled('SampleBooleanFeature');

getValue

var value = abp.features.getValue('SampleNumericFeature');

功能管理者###

如果需要定义功能,可以注入并使用IFeatureManager

版本说明###

ABP没有内置的版本系统,因为这么个系统要求数据库(存储版本,版本功能,租户-版本映射等等)。因此,版本系统实现在了module-zero中了。使用它你可以轻松地拥有一个版本系统,要不然你可以自己实现。

ABP理论学习之功能管理的更多相关文章

  1. ABP理论学习之设置管理

    返回总目录 本篇目录 介绍 定义设置 获取设置值 更改设置 关于缓存 介绍 每个应用程序都需要存储一些设置信息,然后在应用程序中的某个地方使用这些设置.ABP提供了健壮的基础设施来存储或检索服务端和客 ...

  2. ABP框架 - 功能管理

    文档目录 本节内容: 简介 关于 IFeatureValueStore 功能类型 Boolean 功能 Value 功能 定义功能 基本功能属性 其它功能属性 功能层次 检查功能 使用Requires ...

  3. ABP理论学习之MVC视图

    返回总目录 本篇目录 介绍 AbpWebViewPage基类 介绍 ABP通过Abp.Web.Mvc Nuget包集成了MVC视图.因此你可以像常规那样创建MVC视图. AbpWebViewPage基 ...

  4. ABP理论学习之Javascript API(理论完结篇)

    返回总目录 本篇目录 Ajax Notification Message UI block和busy 事件总线 Logging 其他工具功能 说在前面的话 不知不觉,我们送走了2015,同时迎来了20 ...

  5. AspnetBoilerplate (ABP) Organization Units 组织结构管理

    ABP是一个成熟的.NET框架,功能完善.目前由于项目需要正在自学中. ABP对于组织节点管理这一基本上每个项目都要反复重复开发的内容,进行了自己的实现. 主要包括这些常用功能: 多租户 树结构管理的 ...

  6. X-Admin&ABP框架开发-设置管理

    在网站开发中,设置是不可缺少的一环,如用户设置.系统设置.甚至是租户设置等.ABP对于设置的管理已经做了很好的处理,我们可以借助巨人的力量来完成我们的冒险. ABP官网地址:https://aspne ...

  7. Asp.Net Core 项目实战之权限管理系统(6) 功能管理

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

  8. ABP理论学习之仓储

    返回总目录 本篇目录 IRepository接口 查询 插入 更新 删除 其他 关于异步方法 仓储实现 管理数据库连接 仓储的生命周期 仓储最佳实践 Martin Fowler对仓储的定义 位于领域层 ...

  9. Xianfeng轻量级Java中间件平台:功能管理

    功能管理:从功能类型来看,不属于用户使用的功能,而属于系统维护使用的功能,因为对于用户来说,是不可见的.功能管理的作用是定义一套规则,用来处理权限等业务,比如常见的菜单权限控制.按钮权限控制等情景 在 ...

随机推荐

  1. Dapper入门学习

    今天了解并学习了下Dapper的用法,这里简单介绍下 1.安装Nuget Dapper Package包 2.代码 using (IDbConnection connection = new SqlC ...

  2. 【DWR系列06】- DWR日志及js压缩

    img { border: solid 1px } 一.日志 DWR依赖 Apache Commons Logging,可以使用log4j实现日志记录功能. 1.1 日志简介 和其他日志框架一样,当设 ...

  3. NFC读写实例

    package com.sy.nfc.test; import java.io.IOException; import android.nfc.NdefMessage; import android. ...

  4. VS Code 配置Python

    1. 安装VS Code的Python插件,选择安装次数最多的那个 2. 点击用户设置菜单,在settings.json中添加 "python.pythonPath": " ...

  5. 关于 js 一些基本的东西

    r.js 可以打包(可以实现前端文件的压缩与合并). 客户端尽量遵循 amd 规范. 推荐使用 requirejs 规范. requirejs 简单教程: http://www.runoob.com/ ...

  6. dos下对mysql的简单操作(linux类似)

    >>>>>>>>>>>>>>>>>>>> 基础入门语句10条 1. 连接服务器  ...

  7. Linux学习笔记(12)-进程间通信|匿名管道

    Linux的进程间通信有几种方式,包括,管道,信号,信号灯,共享内存,消息队列和套接字等-- 现在一个个的开始学习! ----------------------------------------- ...

  8. hive学习笔记

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  9. 一些VS2013的使用技巧

    作者:h46incon的Blog 1. Peek View 可以在不新建TAB的情况下快速查看.编辑一个函数的代码. 用法:在光标移至某个函数下,按下alt+F12. 然后在Peek窗口里可以继续按a ...

  10. curl模拟post,get,put,delete

    安装curl:https://curl.haxx.se/download.html 测试:tomcat默认禁用put,delete返回403 GET curl -HAccept:text/plain ...