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 |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpLocalizationModule), |
|||
typeof(AbpVirtualFileSystemModule) |
|||
)] |
|||
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