4.6 KiB
Global Features
Global Feature system is used to enable/disable an application feature on development time. It is done on the development time, because some services (e.g. controllers) are removed from the application model and database tables are not created for the disabled features, which is not possible on runtime.
Global Features system is especially useful if you want to develop a reusable application module with optional features. If the final application doesn't want to use some of the features, it can disable these features.
If you are looking for a system to enable/disable features based on current tenant or any other condition, please see the Features document.
Installation
This package is already installed by default with the startup template. So, most of the time, you don't need to install it manually.
Using the ABP CLI
Open a command line window in the folder of the project (.csproj file) and type the following command:
abp add-package Volo.Abp.GlobalFeatures
Defining a Global Feature
A feature class is something like that:
[GlobalFeatureName("Shopping.Payment")]
public class PaymentFeature
{
}
Enable/Disable Global Features
Use GlobalFeatureManager.Instance
to enable/disable a global feature.
// Able to Enable/Disable with generic type parameter.
GlobalFeatureManager.Instance.Enable<PaymentFeature>();
GlobalFeatureManager.Instance.Disable<PaymentFeature>();
// Also able to Enable/Disable with string feature name.
GlobalFeatureManager.Instance.Enable("Shopping.Payment");
GlobalFeatureManager.Instance.Disable("Shopping.Payment");
Global Features are disabled unless they are explicitly enabled.
Where to Configure Global Features?
Global Features have to be configured before application startup. Since the GlobalFeatureManager.Instance
is a singleton object, one-time, static configuration is enough. It is suggested to enable/disable global features in PreConfigureServices
method of your module. You can use the OneTimeRunner
utility class to make sure it runs only once:
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public override void PreConfigureServices(ServiceConfigurationContext context)
{
OneTimeRunner.Run(() =>
{
GlobalFeatureManager.Instance.Enable<PaymentFeature>();
});
}
Check for a Global Feature
GlobalFeatureManager.Instance.IsEnabled<PaymentFeature>()
GlobalFeatureManager.Instance.IsEnabled("Shopping.Payment")
Both methods return bool
. So, you can write conditional logic as shown below:
if (GlobalFeatureManager.Instance.IsEnabled<PaymentFeature>())
{
// Some strong payment codes here...
}
RequiresGlobalFeature Attribute
Beside the manual check, there is [RequiresGlobalFeature]
attribute to check it declaratively for a controller or page. ABP returns HTTP Response 404
if the related feature was disabled.
[RequiresGlobalFeature(typeof(PaymentFeature))]
public class PaymentController : AbpController
{
}
Grouping Features of a Module
It is common to group global features of a module to allow the final application developer easily discover and configure the features.
Following example shows how to group features of a module.
[GlobalFeatureName("Ecommerce.Subscription")]
public class SubscriptionFeature : GlobalFeature
{
public SubscriptionFeature(GlobalModuleFeatures module) : base(module)
{
}
}
All features of a module have to be defined in a Global Module Features class.
public class GlobalEcommerceFeatures : GlobalModuleFeatures
{
public const string ModuleName = "Ecommerce";
public SubscriptionFeature Subscription => GetFeature<SubscriptionFeature>();
public GlobalEcommerceFeatures(GlobalFeatureManager featureManager) : base(featureManager)
{
// Added features will be used for EnableAll() & DisableAll() actions for this module.
AddFeature(new SubscriptionFeature(this));
}
}
An extension method will be better to discover Global Module Features class
public static class GlobalModuleFeaturesDictionaryEcommerceExtensions
{
public static GlobalEcommerceFeatures Ecommerce([NotNull] this GlobalModuleFeaturesDictionary modules)
{
Check.NotNull(modules, nameof(modules));
return modules
.GetOrAdd(
GlobalEcommerceFeatures.ModuleName,
_ => new GlobalEcommerceFeatures(modules.FeatureManager)
)
as GlobalEcommerceFeatures;
}
Final usage will be like below:
GlobalFeatureManager.Instance.Modules.Ecommerce().Subscription.Enable();