mirror of https://github.com/abpframework/abp.git
26 changed files with 352 additions and 29 deletions
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public class AbpGlobalFeatureErrorCodes |
||||
|
{ |
||||
|
public const string GlobalFeatureIsNotEnabled = "Volo.GlobalFeature:010001"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.ExceptionHandling; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public class AbpGlobalFeatureNotEnableException : AbpException, IHasErrorCode |
||||
|
{ |
||||
|
public string Code { get; } |
||||
|
|
||||
|
public AbpGlobalFeatureNotEnableException(string message = null, string code = null, Exception innerException = null) |
||||
|
: base(message, innerException) |
||||
|
{ |
||||
|
Code = code; |
||||
|
} |
||||
|
|
||||
|
public AbpGlobalFeatureNotEnableException WithData(string name, object value) |
||||
|
{ |
||||
|
Data[name] = value; |
||||
|
return this; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,9 +1,42 @@ |
|||||
using Volo.Abp.Modularity; |
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.GlobalFeatures.Localization; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Localization.ExceptionHandling; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
namespace Volo.Abp.GlobalFeatures |
namespace Volo.Abp.GlobalFeatures |
||||
{ |
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpLocalizationModule), |
||||
|
typeof(AbpVirtualFileSystemModule) |
||||
|
)] |
||||
public class AbpGlobalFeaturesModule : AbpModule |
public class AbpGlobalFeaturesModule : AbpModule |
||||
{ |
{ |
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.OnRegistred(GlobalFeatureInterceptorRegistrar.RegisterIfNeeded); |
||||
|
} |
||||
|
|
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
|
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpGlobalFeatureResource>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Add<AbpGlobalFeatureResource>("en") |
||||
|
.AddVirtualJson("/Volo/Abp/GlobalFeatures/Localization"); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpExceptionLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.MapCodeNamespace("Volo.GlobalFeature", typeof(AbpGlobalFeatureResource)); |
||||
|
}); |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,14 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Reflection; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public static class GlobalFeatureHelper |
||||
|
{ |
||||
|
public static bool IsGlobalFeatureEnabled(Type controllerType, out RequiresGlobalFeatureAttribute attribute) |
||||
|
{ |
||||
|
attribute = ReflectionHelper.GetSingleAttributeOrDefault<RequiresGlobalFeatureAttribute>(controllerType); |
||||
|
return attribute == null || GlobalFeatureManager.Instance.IsEnabled(attribute.GetFeatureName()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Aspects; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.DynamicProxy; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public class GlobalFeatureInterceptor : AbpInterceptor, ITransientDependency |
||||
|
{ |
||||
|
public override async Task InterceptAsync(IAbpMethodInvocation invocation) |
||||
|
{ |
||||
|
if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpCrossCuttingConcerns.GlobalFeatureChecking)) |
||||
|
{ |
||||
|
await invocation.ProceedAsync(); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!GlobalFeatureHelper.IsGlobalFeatureEnabled(invocation.TargetObject.GetType(), out var attribute)) |
||||
|
{ |
||||
|
throw new AbpGlobalFeatureNotEnableException(code: AbpGlobalFeatureErrorCodes.GlobalFeatureIsNotEnabled) |
||||
|
.WithData("ServiceName", invocation.TargetObject.GetType().FullName) |
||||
|
.WithData("GlobalFeatureName", attribute.Name); |
||||
|
} |
||||
|
|
||||
|
await invocation.ProceedAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.DynamicProxy; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public static class GlobalFeatureInterceptorRegistrar |
||||
|
{ |
||||
|
public static void RegisterIfNeeded(IOnServiceRegistredContext context) |
||||
|
{ |
||||
|
if (ShouldIntercept(context.ImplementationType)) |
||||
|
{ |
||||
|
context.Interceptors.TryAdd<GlobalFeatureInterceptor>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static bool ShouldIntercept(Type type) |
||||
|
{ |
||||
|
return !DynamicProxyIgnoreTypes.Contains(type) && typeof(IGlobalFeatureCheckingEnabled).IsAssignableFrom(type); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public interface IGlobalFeatureCheckingEnabled |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures.Localization |
||||
|
{ |
||||
|
[LocalizationResourceName("AbpGlobalFeature")] |
||||
|
public class AbpGlobalFeatureResource |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"Volo.GlobalFeature:010001": "The '{ServiceName}' service needs to enable '{GlobalFeatureName}' feature." |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "tr", |
||||
|
"texts": { |
||||
|
"Volo.GlobalFeature:010001": "'{ServiceName}' hizmetinin '{GlobalFeatureName}' özelliğini etkinleştirmesi gerekiyor." |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"Volo.GlobalFeature:010001": "'{ServiceName}'服务需要启用'{GlobalFeatureName}'功能." |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hant", |
||||
|
"texts": { |
||||
|
"Volo.GlobalFeature:010001": "'{ServiceName}'服務需要啟用'{GlobalFeatureName}'功能." |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using Shouldly; |
||||
|
using Volo.Abp.AspNetCore.ExceptionHandling; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public class AbpGlobalFeatureNotEnableException_Localization_Test : GlobalFeatureTestBase |
||||
|
{ |
||||
|
private readonly IExceptionToErrorInfoConverter _exceptionToErrorInfoConverter; |
||||
|
|
||||
|
public AbpGlobalFeatureNotEnableException_Localization_Test() |
||||
|
{ |
||||
|
_exceptionToErrorInfoConverter = GetRequiredService<IExceptionToErrorInfoConverter>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void AbpAuthorizationException_Localization() |
||||
|
{ |
||||
|
using (CultureHelper.Use("zh-Hans")) |
||||
|
{ |
||||
|
var exception = new AbpGlobalFeatureNotEnableException(code: AbpGlobalFeatureErrorCodes.GlobalFeatureIsNotEnabled) |
||||
|
.WithData("ServiceName", "MyService") |
||||
|
.WithData("GlobalFeatureName", "TestFeature");; |
||||
|
var errorInfo = _exceptionToErrorInfoConverter.Convert(exception, false); |
||||
|
errorInfo.Message.ShouldBe("'MyService'服务需要启用'TestFeature'功能."); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,61 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public class GlobalFeatureInterceptor_Tests : GlobalFeatureTestBase |
||||
|
{ |
||||
|
private readonly TestAppServiceV1 _testAppServiceV1; |
||||
|
private readonly TestAppServiceV2 _testAppServiceV2; |
||||
|
|
||||
|
public GlobalFeatureInterceptor_Tests() |
||||
|
{ |
||||
|
_testAppServiceV1 = GetRequiredService<TestAppServiceV1>(); |
||||
|
_testAppServiceV2 = GetRequiredService<TestAppServiceV2>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Interceptor_Test() |
||||
|
{ |
||||
|
var ex = await Assert.ThrowsAsync<AbpGlobalFeatureNotEnableException>(async () => |
||||
|
{ |
||||
|
await _testAppServiceV1.TestMethod(); |
||||
|
}); |
||||
|
|
||||
|
ex.Data["ServiceName"].ShouldBe(_testAppServiceV1.GetType().FullName); |
||||
|
ex.Data["GlobalFeatureName"].ShouldBe(TestFeature.Name); |
||||
|
|
||||
|
GlobalFeatureManager.Instance.Enable(TestFeature.Name); |
||||
|
|
||||
|
(await _testAppServiceV1.TestMethod()).ShouldBe(1); |
||||
|
(await _testAppServiceV2.TestMethod()).ShouldBe(1); |
||||
|
} |
||||
|
|
||||
|
public interface ITestAppService : IApplicationService |
||||
|
{ |
||||
|
Task<int> TestMethod(); |
||||
|
} |
||||
|
|
||||
|
[RequiresGlobalFeature(TestFeature.Name)] |
||||
|
[ExposeServices(typeof(TestAppServiceV1))] |
||||
|
public class TestAppServiceV1 : ApplicationService, ITestAppService |
||||
|
{ |
||||
|
public virtual Task<int> TestMethod() |
||||
|
{ |
||||
|
return Task.FromResult(1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[ExposeServices(typeof(TestAppServiceV2))] |
||||
|
public class TestAppServiceV2 : ApplicationService, ITestAppService |
||||
|
{ |
||||
|
public virtual Task<int> TestMethod() |
||||
|
{ |
||||
|
return Task.FromResult(1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp.Testing; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public abstract class GlobalFeatureTestBase : AbpIntegratedTest<GlobalFeatureTestModule> |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using Volo.Abp.Application; |
||||
|
using Volo.Abp.Autofac; |
||||
|
using Volo.Abp.ExceptionHandling; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
[DependsOn(typeof(AbpAutofacModule))] |
||||
|
[DependsOn(typeof(AbpGlobalFeaturesModule))] |
||||
|
[DependsOn(typeof(AbpDddApplicationModule))] |
||||
|
[DependsOn(typeof(AbpExceptionHandlingModule))] |
||||
|
public class GlobalFeatureTestModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
[GlobalFeatureName(Name)] |
||||
|
public class TestFeature : Abp.GlobalFeatures.GlobalFeature |
||||
|
{ |
||||
|
public const string Name = "TestFeature1"; |
||||
|
|
||||
|
internal TestFeature(TestGlobalModuleFeatures testGlobalModule) |
||||
|
: base(testGlobalModule) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class TestGlobalModuleFeatures : GlobalModuleFeatures |
||||
|
{ |
||||
|
public const string ModuleName = "GlobalFeatureTest"; |
||||
|
|
||||
|
public TestFeature Test => GetFeature<TestFeature>(); |
||||
|
|
||||
|
public TestGlobalModuleFeatures(GlobalFeatureManager featureManager) |
||||
|
: base(featureManager) |
||||
|
{ |
||||
|
AddFeature(new TestFeature(this)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue