# 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](Features.md) 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: ```bash abp add-package Volo.Abp.GlobalFeatures ``` ## Defining a Global Feature A feature class is something like that: ```csharp [GlobalFeatureName("Shopping.Payment")] public class PaymentFeature { } ``` ## Enable/Disable Global Features Use `GlobalFeatureManager.Instance` to enable/disable a global feature. ```csharp // Able to Enable/Disable with generic type parameter. GlobalFeatureManager.Instance.Enable(); GlobalFeatureManager.Instance.Disable(); // 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: ```csharp private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); public override void PreConfigureServices(ServiceConfigurationContext context) { OneTimeRunner.Run(() => { GlobalFeatureManager.Instance.Enable(); }); } ``` ## Check for a Global Feature ```csharp GlobalFeatureManager.Instance.IsEnabled() GlobalFeatureManager.Instance.IsEnabled("Shopping.Payment") ``` Both methods return `bool`. So, you can write conditional logic as shown below: ```csharp if (GlobalFeatureManager.Instance.IsEnabled()) { // 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. ```csharp [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. ```csharp [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. ```csharp public class GlobalEcommerceFeatures : GlobalModuleFeatures { public const string ModuleName = "Ecommerce"; public SubscriptionFeature Subscription => GetFeature(); 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 ```csharp 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: ```csharp GlobalFeatureManager.Instance.Modules.Ecommerce().Subscription.Enable(); ```