diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 5778b054ed..3811a80ee8 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -323,6 +323,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Aws", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Aws.Tests", "test\Volo.Abp.BlobStoring.Aws.Tests\Volo.Abp.BlobStoring.Aws.Tests.csproj", "{2CD3B26A-CA81-4279-8D5D-6A594517BB3F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.GlobalFeatures", "src\Volo.Abp.GlobalFeatures\Volo.Abp.GlobalFeatures.csproj", "{04F44063-C952-403A-815F-EFB778BDA125}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.GlobalFeatures.Tests", "test\Volo.Abp.GlobalFeatures.Tests\Volo.Abp.GlobalFeatures.Tests.csproj", "{231F1581-AA21-44C3-BF27-51EB3AD5355C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -961,6 +965,14 @@ Global {2CD3B26A-CA81-4279-8D5D-6A594517BB3F}.Debug|Any CPU.Build.0 = Debug|Any CPU {2CD3B26A-CA81-4279-8D5D-6A594517BB3F}.Release|Any CPU.ActiveCfg = Release|Any CPU {2CD3B26A-CA81-4279-8D5D-6A594517BB3F}.Release|Any CPU.Build.0 = Release|Any CPU + {04F44063-C952-403A-815F-EFB778BDA125}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04F44063-C952-403A-815F-EFB778BDA125}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04F44063-C952-403A-815F-EFB778BDA125}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04F44063-C952-403A-815F-EFB778BDA125}.Release|Any CPU.Build.0 = Release|Any CPU + {231F1581-AA21-44C3-BF27-51EB3AD5355C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {231F1581-AA21-44C3-BF27-51EB3AD5355C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {231F1581-AA21-44C3-BF27-51EB3AD5355C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {231F1581-AA21-44C3-BF27-51EB3AD5355C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1124,6 +1136,8 @@ Global {8E49687A-E69F-49F2-8DB0-428D0883A937} = {447C8A77-E5F0-4538-8687-7383196D04EA} {50968CDE-1029-4051-B2E5-B69D0ECF2A18} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {2CD3B26A-CA81-4279-8D5D-6A594517BB3F} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {04F44063-C952-403A-815F-EFB778BDA125} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {231F1581-AA21-44C3-BF27-51EB3AD5355C} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.GlobalFeatures/FodyWeavers.xml b/framework/src/Volo.Abp.GlobalFeatures/FodyWeavers.xml new file mode 100644 index 0000000000..bc5a74a236 --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/framework/src/Volo.Abp.GlobalFeatures/FodyWeavers.xsd b/framework/src/Volo.Abp.GlobalFeatures/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.GlobalFeatures/Properties/AssemblyInfo.cs b/framework/src/Volo.Abp.GlobalFeatures/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..e4ff8a95bd --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly:InternalsVisibleTo("Volo.Abp.GlobalFeatures.Tests")] diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo.Abp.GlobalFeatures.csproj b/framework/src/Volo.Abp.GlobalFeatures/Volo.Abp.GlobalFeatures.csproj new file mode 100644 index 0000000000..f4afe8f9f7 --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo.Abp.GlobalFeatures.csproj @@ -0,0 +1,21 @@ + + + + + + + netstandard2.0 + Volo.Abp.GlobalFeatures + Volo.Abp.GlobalFeatures + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/AbpGlobalFeaturesModule.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/AbpGlobalFeaturesModule.cs new file mode 100644 index 0000000000..d537e9f8fd --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/AbpGlobalFeaturesModule.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Modularity; + +namespace Volo.Abp.GlobalFeatures +{ + public class AbpGlobalFeaturesModule : AbpModule + { + + } +} diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeature.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeature.cs new file mode 100644 index 0000000000..c7fc9304a8 --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeature.cs @@ -0,0 +1,51 @@ +using JetBrains.Annotations; + +namespace Volo.Abp.GlobalFeatures +{ + public abstract class GlobalFeature + { + [NotNull] + public GlobalModuleFeatures Module { get; } + + [NotNull] + public GlobalFeatureManager FeatureManager { get; } + + [NotNull] + public string FeatureName { get; } + + public bool IsEnabled + { + get => FeatureManager.IsEnabled(FeatureName); + set => SetEnabled(value); + } + + protected GlobalFeature([NotNull] GlobalModuleFeatures module) + { + Module = Check.NotNull(module, nameof(module)); + FeatureManager = Module.FeatureManager; + FeatureName = GlobalFeatureNameAttribute.GetName(GetType()); + } + + public virtual void Enable() + { + FeatureManager.Enable(FeatureName); + } + + public virtual void Disable() + { + FeatureManager.Disable(FeatureName); + } + + public void SetEnabled(bool isEnabled) + { + if (isEnabled) + { + Enable(); + } + else + { + Disable(); + } + } + } +} diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeatureDictionary.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeatureDictionary.cs new file mode 100644 index 0000000000..a81632f8d5 --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeatureDictionary.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Volo.Abp.GlobalFeatures +{ + public class GlobalFeatureDictionary : Dictionary + { + + } +} diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeatureManager.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeatureManager.cs new file mode 100644 index 0000000000..79badfe4e7 --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeatureManager.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using JetBrains.Annotations; + +namespace Volo.Abp.GlobalFeatures +{ + public class GlobalFeatureManager + { + public static GlobalFeatureManager Instance { get; protected set; } = new GlobalFeatureManager(); + + /// + /// A common dictionary to store arbitrary configurations. + /// + [NotNull] + public Dictionary Configuration { get; } + + public GlobalModuleFeaturesDictionary Modules { get; } + + protected HashSet EnabledFeatures { get; } + + internal GlobalFeatureManager() + { + EnabledFeatures = new HashSet(); + Configuration = new Dictionary(); + Modules = new GlobalModuleFeaturesDictionary(this); + } + + public virtual bool IsEnabled() + where TFeature : GlobalFeature + { + return IsEnabled(GlobalFeatureNameAttribute.GetName()); + } + + public virtual bool IsEnabled(string featureName) + { + return EnabledFeatures.Contains(featureName); + } + + protected internal void Enable(string featureName) + { + EnabledFeatures.AddIfNotContains(featureName); + } + + protected internal void Disable(string featureName) + { + EnabledFeatures.Remove(featureName); + } + + public virtual IEnumerable GetEnabledFeatureNames() + { + return EnabledFeatures; + } + } +} diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeatureNameAttribute.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeatureNameAttribute.cs new file mode 100644 index 0000000000..0563712899 --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeatureNameAttribute.cs @@ -0,0 +1,42 @@ +using System; +using System.Linq; +using System.Reflection; +using JetBrains.Annotations; + +namespace Volo.Abp.GlobalFeatures +{ + [AttributeUsage(AttributeTargets.Class)] + public class GlobalFeatureNameAttribute : Attribute + { + [NotNull] + public string Name { get; } + + public GlobalFeatureNameAttribute([NotNull] string name) + { + Name = Check.NotNullOrWhiteSpace(name, nameof(name)); + } + + public static string GetName() + where TFeature : GlobalFeature + { + return GetName(typeof(TFeature)); + } + + [NotNull] + public static string GetName(Type type) + { + var attribute = type + .GetCustomAttributes() + .FirstOrDefault(); + + if (attribute == null) + { + throw new AbpException($"{type.AssemblyQualifiedName} should define the {typeof(GlobalFeatureNameAttribute).FullName} atttribute!"); + } + + return attribute + .As() + .Name; + } + } +} diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalModuleFeatures.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalModuleFeatures.cs new file mode 100644 index 0000000000..7d1b844d45 --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalModuleFeatures.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using JetBrains.Annotations; + +namespace Volo.Abp.GlobalFeatures +{ + public abstract class GlobalModuleFeatures + { + [NotNull] + public GlobalFeatureManager FeatureManager { get; } + + [NotNull] + protected GlobalFeatureDictionary AllFeatures { get; } + + protected GlobalModuleFeatures( + [NotNull] GlobalFeatureManager featureManager) + { + FeatureManager = Check.NotNull(featureManager, nameof(featureManager)); + AllFeatures = new GlobalFeatureDictionary(); + } + + public virtual void Enable() + where TFeature : GlobalFeature + { + GetFeature().Enable(); + } + + public virtual void Disable() + where TFeature : GlobalFeature + { + GetFeature().Disable(); + } + + public virtual void SetEnabled(bool isEnabled) + where TFeature : GlobalFeature + { + GetFeature().SetEnabled(isEnabled); + } + + public virtual void Enable(string featureName) + { + GetFeature(featureName).Enable(); + } + + public virtual void Disable(string featureName) + { + GetFeature(featureName).Disable(); + } + + public virtual void SetEnabled(string featureName, bool isEnabled) + { + GetFeature(featureName).SetEnabled(isEnabled); + } + + public virtual void EnableAll() + { + foreach (var feature in AllFeatures.Values) + { + feature.Enable(); + } + } + + public virtual void DisableAll() + { + foreach (var feature in AllFeatures.Values) + { + feature.Disable(); + } + } + + public virtual GlobalFeature GetFeature(string featureName) + { + var feature = AllFeatures.GetOrDefault(featureName); + if (feature == null) + { + throw new AbpException($"There is no feature defined by name '{featureName}'."); + } + + return feature; + } + + public virtual TFeature GetFeature() + where TFeature : GlobalFeature + { + return (TFeature) GetFeature(GlobalFeatureNameAttribute.GetName()); + } + + public virtual IReadOnlyList GetFeatures() + { + return AllFeatures.Values.ToImmutableList(); + } + + protected void AddFeature(GlobalFeature feature) + { + AllFeatures[feature.FeatureName] = feature; + } + } +} diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalModuleFeaturesDictionary.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalModuleFeaturesDictionary.cs new file mode 100644 index 0000000000..b89bf2fe36 --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalModuleFeaturesDictionary.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using JetBrains.Annotations; + +namespace Volo.Abp.GlobalFeatures +{ + public class GlobalModuleFeaturesDictionary : Dictionary + { + public GlobalFeatureManager FeatureManager { get; } + + public GlobalModuleFeaturesDictionary( + [NotNull] GlobalFeatureManager featureManager) + { + FeatureManager = Check.NotNull(featureManager, nameof(featureManager)); + } + } +} diff --git a/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo.Abp.GlobalFeatures.Tests.csproj b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo.Abp.GlobalFeatures.Tests.csproj new file mode 100644 index 0000000000..c0a973f8a5 --- /dev/null +++ b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo.Abp.GlobalFeatures.Tests.csproj @@ -0,0 +1,16 @@ + + + + + + netcoreapp3.1 + + + + + + + + + + diff --git a/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeatureManager_Tests.cs b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeatureManager_Tests.cs new file mode 100644 index 0000000000..6d8e3a9d25 --- /dev/null +++ b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeatureManager_Tests.cs @@ -0,0 +1,23 @@ +using Shouldly; +using Xunit; + +namespace Volo.Abp.GlobalFeatures +{ + public class GlobalFeatureManager_Tests + { + private readonly GlobalFeatureManager _featureManeger; + + public GlobalFeatureManager_Tests() + { + _featureManeger = new GlobalFeatureManager(); + } + + [Fact] + public void Enable_Feature_By_Name() + { + _featureManeger.IsEnabled("Feature1").ShouldBeFalse(); + _featureManeger.Enable("Feature1"); + _featureManeger.IsEnabled("Feature1").ShouldBeTrue(); + } + } +} diff --git a/modules/cms-kit/host/Volo.CmsKit.Host.Shared/FeatureConfigurer.cs b/modules/cms-kit/host/Volo.CmsKit.Host.Shared/FeatureConfigurer.cs new file mode 100644 index 0000000000..9046c60aca --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Host.Shared/FeatureConfigurer.cs @@ -0,0 +1,18 @@ +using Volo.Abp.GlobalFeatures; +using Volo.Abp.Threading; + +namespace Volo.CmsKit +{ + public static class FeatureConfigurer + { + private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); + + public static void Configure() + { + OneTimeRunner.Run(() => + { + GlobalFeatureManager.Instance.Modules.CmsKit().EnableAll(); + }); + } + } +} diff --git a/modules/cms-kit/host/Volo.CmsKit.Host.Shared/Volo.CmsKit.Host.Shared.csproj b/modules/cms-kit/host/Volo.CmsKit.Host.Shared/Volo.CmsKit.Host.Shared.csproj index 3f8c167b98..c6a4484865 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Host.Shared/Volo.CmsKit.Host.Shared.csproj +++ b/modules/cms-kit/host/Volo.CmsKit.Host.Shared/Volo.CmsKit.Host.Shared.csproj @@ -7,4 +7,8 @@ Volo.CmsKit + + + + diff --git a/modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/CmsKitHttpApiHostModule.cs b/modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/CmsKitHttpApiHostModule.cs index c63d28081f..f1a9b8568f 100644 --- a/modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/CmsKitHttpApiHostModule.cs +++ b/modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/CmsKitHttpApiHostModule.cs @@ -52,6 +52,11 @@ namespace Volo.CmsKit { private const string DefaultCorsPolicyName = "Default"; + public override void PreConfigureServices(ServiceConfigurationContext context) + { + FeatureConfigurer.Configure(); + } + public override void ConfigureServices(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); @@ -163,7 +168,7 @@ namespace Volo.CmsKit app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); - app.UseCors(DefaultCorsPolicyName); + app.UseCors(DefaultCorsPolicyName); app.UseAuthentication(); app.UseAbpClaimsMap(); if (MultiTenancyConsts.IsEnabled) diff --git a/modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/EntityFrameworkCore/CmsKitHttpApiHostMigrationsDbContextFactory.cs b/modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/EntityFrameworkCore/CmsKitHttpApiHostMigrationsDbContextFactory.cs index 3a6dbb47ad..dc19e09635 100644 --- a/modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/EntityFrameworkCore/CmsKitHttpApiHostMigrationsDbContextFactory.cs +++ b/modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/EntityFrameworkCore/CmsKitHttpApiHostMigrationsDbContextFactory.cs @@ -9,6 +9,8 @@ namespace Volo.CmsKit.EntityFrameworkCore { public CmsKitHttpApiHostMigrationsDbContext CreateDbContext(string[] args) { + FeatureConfigurer.Configure(); + var configuration = BuildConfiguration(); var builder = new DbContextOptionsBuilder() diff --git a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/CmsKitIdentityServerModule.cs b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/CmsKitIdentityServerModule.cs index faf90a3fc2..b9afe934a3 100644 --- a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/CmsKitIdentityServerModule.cs +++ b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/CmsKitIdentityServerModule.cs @@ -77,6 +77,11 @@ namespace Volo.CmsKit { private const string DefaultCorsPolicyName = "Default"; + public override void PreConfigureServices(ServiceConfigurationContext context) + { + FeatureConfigurer.Configure(); + } + public override void ConfigureServices(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); @@ -182,10 +187,10 @@ namespace Volo.CmsKit app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); - app.UseCors(DefaultCorsPolicyName); + app.UseCors(DefaultCorsPolicyName); app.UseAuthentication(); app.UseJwtTokenMiddleware(); - + if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); diff --git a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/EntityFrameworkCore/IdentityServerHostMigrationsDbContextFactory.cs b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/EntityFrameworkCore/IdentityServerHostMigrationsDbContextFactory.cs index f6e80d62ec..19402b80c1 100644 --- a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/EntityFrameworkCore/IdentityServerHostMigrationsDbContextFactory.cs +++ b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/EntityFrameworkCore/IdentityServerHostMigrationsDbContextFactory.cs @@ -9,6 +9,8 @@ namespace Volo.CmsKit.EntityFrameworkCore { public IdentityServerHostMigrationsDbContext CreateDbContext(string[] args) { + FeatureConfigurer.Configure(); + var configuration = BuildConfiguration(); var builder = new DbContextOptionsBuilder() diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Host/CmsKitWebHostModule.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Host/CmsKitWebHostModule.cs index 95946c54df..7587b075d0 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Host/CmsKitWebHostModule.cs +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Host/CmsKitWebHostModule.cs @@ -65,6 +65,8 @@ namespace Volo.CmsKit { public override void PreConfigureServices(ServiceConfigurationContext context) { + FeatureConfigurer.Configure(); + context.Services.PreConfigure(options => { options.AddAssemblyResource( @@ -222,7 +224,7 @@ namespace Volo.CmsKit app.UseHttpsRedirection(); app.UseVirtualFiles(); app.UseRouting(); - app.UseAuthentication(); + app.UseAuthentication(); if (MultiTenancyConsts.IsEnabled) { diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/CmsKitWebUnifiedModule.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/CmsKitWebUnifiedModule.cs index b1cd636ef0..08dadb3dd6 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/CmsKitWebUnifiedModule.cs +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/CmsKitWebUnifiedModule.cs @@ -63,6 +63,11 @@ namespace Volo.CmsKit )] public class CmsKitWebUnifiedModule : AbpModule { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + FeatureConfigurer.Configure(); + } + public override void ConfigureServices(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/EntityFrameworkCore/UnifiedDbContextFactory.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/EntityFrameworkCore/UnifiedDbContextFactory.cs index f2c1d8a065..170e4dc688 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/EntityFrameworkCore/UnifiedDbContextFactory.cs +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/EntityFrameworkCore/UnifiedDbContextFactory.cs @@ -9,6 +9,8 @@ namespace Volo.CmsKit.EntityFrameworkCore { public UnifiedDbContext CreateDbContext(string[] args) { + FeatureConfigurer.Configure(); + var configuration = BuildConfiguration(); var builder = new DbContextOptionsBuilder() diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.csproj b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.csproj index 03bc3bce5d..e5e84b7aca 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.csproj +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.csproj @@ -11,6 +11,7 @@ + diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/Abp/GlobalFeatures/GlobalModuleFeaturesDictionaryCmsKitExtensions.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/Abp/GlobalFeatures/GlobalModuleFeaturesDictionaryCmsKitExtensions.cs new file mode 100644 index 0000000000..72701d5e4d --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/Abp/GlobalFeatures/GlobalModuleFeaturesDictionaryCmsKitExtensions.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using Volo.CmsKit.GlobalFeatures; + +namespace Volo.Abp.GlobalFeatures +{ + public static class GlobalModuleFeaturesDictionaryCmsKitExtensions + { + public static GlobalCmsKitFeatures CmsKit( + [NotNull] this GlobalModuleFeaturesDictionary modules) + { + Check.NotNull(modules, nameof(modules)); + + return modules + .GetOrAdd( + GlobalCmsKitFeatures.ModuleName, + _ => new GlobalCmsKitFeatures(modules.FeatureManager) + ) + as GlobalCmsKitFeatures; + } + + public static GlobalModuleFeaturesDictionary CmsKit( + [NotNull] this GlobalModuleFeaturesDictionary modules, + [NotNull] Action configureAction) + { + Check.NotNull(configureAction, nameof(configureAction)); + + configureAction(modules.CmsKit()); + + return modules; + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitDomainSharedModule.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitDomainSharedModule.cs index 925acdaf79..d2490cfb37 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitDomainSharedModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitDomainSharedModule.cs @@ -1,4 +1,6 @@ -using Volo.Abp.Modularity; +using System; +using Volo.Abp.GlobalFeatures; +using Volo.Abp.Modularity; using Volo.Abp.Localization; using Volo.CmsKit.Localization; using Volo.Abp.Localization.ExceptionHandling; @@ -9,7 +11,8 @@ using Volo.Abp.VirtualFileSystem; namespace Volo.CmsKit { [DependsOn( - typeof(AbpValidationModule) + typeof(AbpValidationModule), + typeof(AbpGlobalFeaturesModule) )] public class CmsKitDomainSharedModule : AbpModule { diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/CommentsFeature.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/CommentsFeature.cs new file mode 100644 index 0000000000..a812bd5388 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/CommentsFeature.cs @@ -0,0 +1,18 @@ +using JetBrains.Annotations; +using Volo.Abp.GlobalFeatures; + +namespace Volo.CmsKit.GlobalFeatures +{ + [GlobalFeatureName(Name)] + public class CommentsFeature : GlobalFeature + { + public const string Name = "CmsKit.Comments"; + + internal CommentsFeature( + [NotNull] GlobalCmsKitFeatures cmsKit + ) : base(cmsKit) + { + + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/GlobalCmsKitFeatures.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/GlobalCmsKitFeatures.cs new file mode 100644 index 0000000000..646a91ef4f --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/GlobalCmsKitFeatures.cs @@ -0,0 +1,21 @@ +using JetBrains.Annotations; +using Volo.Abp.GlobalFeatures; + +namespace Volo.CmsKit.GlobalFeatures +{ + public class GlobalCmsKitFeatures : GlobalModuleFeatures + { + public const string ModuleName = "CmsKit"; + + public ReactionsFeature Reactions => GetFeature(); + + public CommentsFeature Comments => GetFeature(); + + public GlobalCmsKitFeatures([NotNull] GlobalFeatureManager featureManager) + : base(featureManager) + { + AddFeature(new ReactionsFeature(this)); + AddFeature(new CommentsFeature(this)); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/ReactionsFeature.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/ReactionsFeature.cs new file mode 100644 index 0000000000..ad9a60b64d --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/ReactionsFeature.cs @@ -0,0 +1,17 @@ +using JetBrains.Annotations; +using Volo.Abp.GlobalFeatures; + +namespace Volo.CmsKit.GlobalFeatures +{ + [GlobalFeatureName(Name)] + public class ReactionsFeature : GlobalFeature + { + public const string Name = "CmsKit.Reactions"; + + internal ReactionsFeature( + [NotNull] GlobalCmsKitFeatures cmsKit + ) : base(cmsKit) + { + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Comments/EfCoreCommentRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Comments/EfCoreCommentRepository.cs index 00b3150219..6a1b8d6a50 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Comments/EfCoreCommentRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Comments/EfCoreCommentRepository.cs @@ -8,6 +8,7 @@ using Volo.Abp; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; using Volo.CmsKit.EntityFrameworkCore; +using Volo.CmsKit.Users; namespace Volo.CmsKit.Comments { @@ -27,7 +28,7 @@ namespace Volo.CmsKit.Comments Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); var query = from comment in DbSet - join user in DbContext.CmsUsers on comment.CreatorId equals user.Id + join user in DbContext.Set() on comment.CreatorId equals user.Id where entityType == comment.EntityType && entityId == comment.EntityId orderby comment.CreationTime select new CommentWithAuthorQueryResultItem diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs index 8033522f70..65d9b55181 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs @@ -1,21 +1,12 @@ using Microsoft.EntityFrameworkCore; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; -using Volo.CmsKit.Comments; -using Volo.CmsKit.Reactions; -using Volo.CmsKit.Users; namespace Volo.CmsKit.EntityFrameworkCore { [ConnectionStringName(CmsKitDbProperties.ConnectionStringName)] public class CmsKitDbContext : AbpDbContext, ICmsKitDbContext { - public DbSet UserReactions { get; set; } - - public DbSet Comments { get; set; } - - public DbSet CmsUsers { get; set; } - public CmsKitDbContext(DbContextOptions options) : base(options) { diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs index e945ddc7ed..d1fcaf8211 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs @@ -2,10 +2,12 @@ using Microsoft.EntityFrameworkCore; using Volo.Abp; using Volo.Abp.EntityFrameworkCore.Modeling; +using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Comments; using Volo.CmsKit.Reactions; using Volo.CmsKit.Users; using Volo.Abp.Users.EntityFrameworkCore; +using Volo.CmsKit.GlobalFeatures; namespace Volo.CmsKit.EntityFrameworkCore { @@ -32,34 +34,40 @@ namespace Volo.CmsKit.EntityFrameworkCore b.ConfigureAbpUser(); }); - builder.Entity(b => + if (GlobalFeatureManager.Instance.IsEnabled()) { - b.ToTable(options.TablePrefix + "UserReactions", options.Schema); - b.ConfigureByConvention(); + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "UserReactions", options.Schema); + b.ConfigureByConvention(); - b.Property(x => x.EntityType).IsRequired().HasMaxLength(UserReactionConsts.MaxEntityTypeLength); - b.Property(x => x.EntityId).IsRequired().HasMaxLength(UserReactionConsts.MaxEntityIdLength); - b.Property(x => x.ReactionName).IsRequired().HasMaxLength(UserReactionConsts.MaxReactionNameLength); - b.Property(x => x.CreationTime); + b.Property(x => x.EntityType).IsRequired().HasMaxLength(UserReactionConsts.MaxEntityTypeLength); + b.Property(x => x.EntityId).IsRequired().HasMaxLength(UserReactionConsts.MaxEntityIdLength); + b.Property(x => x.ReactionName).IsRequired().HasMaxLength(UserReactionConsts.MaxReactionNameLength); + b.Property(x => x.CreationTime); - b.HasIndex(x => new { x.EntityType, x.EntityId }); - b.HasIndex(x => new { x.CreatorId, x.EntityType, x.EntityId, x.ReactionName }); - }); + b.HasIndex(x => new { x.EntityType, x.EntityId }); + b.HasIndex(x => new { x.CreatorId, x.EntityType, x.EntityId, x.ReactionName }); + }); + } - builder.Entity(b => + if (GlobalFeatureManager.Instance.IsEnabled()) { - b.ToTable(options.TablePrefix + "Comments", options.Schema); - b.ConfigureByConvention(); + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "Comments", options.Schema); + b.ConfigureByConvention(); - b.Property(x => x.EntityType).IsRequired().HasMaxLength(CommentConsts.MaxEntityTypeLength); - b.Property(x => x.EntityId).IsRequired().HasMaxLength(CommentConsts.MaxEntityIdLength); - b.Property(x => x.Text).IsRequired().HasMaxLength(CommentConsts.MaxTextLength); - b.Property(x => x.RepliedCommentId); - b.Property(x => x.CreationTime); + b.Property(x => x.EntityType).IsRequired().HasMaxLength(CommentConsts.MaxEntityTypeLength); + b.Property(x => x.EntityId).IsRequired().HasMaxLength(CommentConsts.MaxEntityIdLength); + b.Property(x => x.Text).IsRequired().HasMaxLength(CommentConsts.MaxTextLength); + b.Property(x => x.RepliedCommentId); + b.Property(x => x.CreationTime); - b.HasIndex(x => new { x.EntityType, x.EntityId }); - b.HasIndex(x => new { x.RepliedCommentId }); - }); + b.HasIndex(x => new { x.EntityType, x.EntityId }); + b.HasIndex(x => new { x.RepliedCommentId }); + }); + } } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs index e63366d5ae..352335fb7c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs @@ -1,19 +1,10 @@ -using Microsoft.EntityFrameworkCore; -using Volo.Abp.Data; +using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; -using Volo.CmsKit.Comments; -using Volo.CmsKit.Reactions; -using Volo.CmsKit.Users; namespace Volo.CmsKit.EntityFrameworkCore { [ConnectionStringName(CmsKitDbProperties.ConnectionStringName)] public interface ICmsKitDbContext : IEfCoreDbContext { - DbSet UserReactions { get; } - - DbSet Comments { get; } - - DbSet CmsUsers { get; set; } } } diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Comments/CommentPublicAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Comments/CommentPublicAppService_Tests.cs index 9568f79c6f..f02339dde8 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Comments/CommentPublicAppService_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Comments/CommentPublicAppService_Tests.cs @@ -1,11 +1,8 @@ -using System; -using System.Linq; +using System.Linq; using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using NSubstitute; using Shouldly; -using Volo.Abp.MultiTenancy; using Volo.Abp.Users; using Volo.CmsKit.Public.Comments; using Xunit; @@ -54,7 +51,7 @@ namespace Volo.CmsKit.Comments UsingDbContext(context => { - var comments = context.Comments.Where(x => + var comments = context.Set().Where(x => x.EntityId == _cmsKitTestData.EntityId1 && x.EntityType == _cmsKitTestData.EntityType1).ToList(); comments @@ -75,7 +72,7 @@ namespace Volo.CmsKit.Comments UsingDbContext(context => { - var comment = context.Comments.Single(x => + var comment = context.Set().Single(x => x.Id == _cmsKitTestData.CommentWithChildId); comment.Text.ShouldBe("I'm Updated"); @@ -91,7 +88,7 @@ namespace Volo.CmsKit.Comments UsingDbContext(context => { - var comment = context.Comments.FirstOrDefault(x => + var comment = context.Set().FirstOrDefault(x => x.Id == _cmsKitTestData.CommentWithChildId); comment.ShouldBeNull(); diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Reactions/ReactionPublicAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Reactions/ReactionPublicAppService_Tests.cs index dd74a1f1e7..615003efec 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Reactions/ReactionPublicAppService_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Reactions/ReactionPublicAppService_Tests.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using NSubstitute; @@ -69,7 +66,7 @@ namespace Volo.CmsKit.Reactions UsingDbContext(context => { - var reaction = context.UserReactions.FirstOrDefault(x => + var reaction = context.Set().FirstOrDefault(x => x.CreatorId == _cmsKitTestData.User1Id && x.ReactionName == StandardReactions.Hooray && x.EntityId == _cmsKitTestData.EntityId2 && @@ -93,7 +90,7 @@ namespace Volo.CmsKit.Reactions UsingDbContext(context => { - var reaction = context.UserReactions.FirstOrDefault(x => + var reaction = context.Set().FirstOrDefault(x => x.CreatorId == _cmsKitTestData.User1Id && x.ReactionName == StandardReactions.Confused && x.EntityId == _cmsKitTestData.EntityId1 && diff --git a/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Reactions/ReactionManager_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Reactions/ReactionManager_Tests.cs index 6f4fe2425d..453d393bb8 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Reactions/ReactionManager_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Reactions/ReactionManager_Tests.cs @@ -69,7 +69,7 @@ namespace Volo.CmsKit.Reactions UsingDbContext(context => { - var reaction = context.UserReactions.FirstOrDefault(x => + var reaction = context.Set().FirstOrDefault(x => x.CreatorId == _cmsKitTestData.User1Id && x.ReactionName == StandardReactions.Confused && x.EntityId == _cmsKitTestData.EntityId1 && diff --git a/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Comments/CommentRepository_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Comments/CommentRepository_Tests.cs index cf2e936ca8..06a8007683 100644 --- a/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Comments/CommentRepository_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Comments/CommentRepository_Tests.cs @@ -1,7 +1,9 @@ using Volo.CmsKit.Comments; +using Xunit; namespace Volo.CmsKit.MongoDB.Comments { + [Collection(MongoTestCollection.Name)] public class CommentRepository_Tests : CommentRepository_Tests { diff --git a/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Reactions/UserReactionRepository_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Reactions/UserReactionRepository_Tests.cs index 452ee211c5..16740a5803 100644 --- a/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Reactions/UserReactionRepository_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Reactions/UserReactionRepository_Tests.cs @@ -1,7 +1,9 @@ using Volo.CmsKit.Reactions; +using Xunit; namespace Volo.CmsKit.MongoDB.Reactions { + [Collection(MongoTestCollection.Name)] public class UserReactionRepository_Tests : UserReactionRepository_Tests { } diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestBaseModule.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestBaseModule.cs index ae1f0f7296..8e5049f55e 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestBaseModule.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestBaseModule.cs @@ -3,6 +3,7 @@ using Volo.Abp; using Volo.Abp.Authorization; using Volo.Abp.Autofac; using Volo.Abp.Data; +using Volo.Abp.GlobalFeatures; using Volo.Abp.Modularity; using Volo.Abp.Threading; @@ -16,8 +17,15 @@ namespace Volo.CmsKit )] public class CmsKitTestBaseModule : AbpModule { + private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); + public override void ConfigureServices(ServiceConfigurationContext context) { + OneTimeRunner.Run(() => + { + GlobalFeatureManager.Instance.Modules.CmsKit().EnableAll(); + }); + context.Services.AddAlwaysAllowAuthorization(); } diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index 99244d5d6c..58b8cf83cf 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -86,6 +86,7 @@ $projects = ( "framework/src/Volo.Abp.EventBus.RabbitMQ", "framework/src/Volo.Abp.Features", "framework/src/Volo.Abp.FluentValidation", + "framework/src/Volo.Abp.GlobalFeatures", "framework/src/Volo.Abp.Guids", "framework/src/Volo.Abp.HangFire", "framework/src/Volo.Abp.Http.Abstractions",