Skip to content

Commit

Permalink
Merge pull request #8117 from abpframework/maliming/global-feature
Browse files Browse the repository at this point in the history
Create interceptor for global features
  • Loading branch information
hikalkan committed Mar 18, 2021
2 parents e0c1f7d + abaab02 commit f6ab71d
Show file tree
Hide file tree
Showing 26 changed files with 352 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using System;
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Aspects;
using Volo.Abp.DependencyInjection;
using Volo.Abp.GlobalFeatures;
using Volo.Abp.Reflection;

namespace Volo.Abp.AspNetCore.Mvc.GlobalFeatures
{
Expand All @@ -21,21 +21,18 @@ public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionE
return;
}

if (!IsGlobalFeatureEnabled(context.Controller.GetType(), out var attribute))
if (!GlobalFeatureHelper.IsGlobalFeatureEnabled(context.Controller.GetType(), out var attribute))
{
var logger = context.GetService<ILogger<GlobalFeatureActionFilter>>(NullLogger<GlobalFeatureActionFilter>.Instance);
logger.LogWarning($"The '{context.Controller.GetType().FullName}' controller needs to enable '{attribute.Name}' feature.");
context.Result = new NotFoundResult();
return;
}

await next();
}

protected virtual bool IsGlobalFeatureEnabled(Type controllerType, out RequiresGlobalFeatureAttribute attribute)
{
attribute = ReflectionHelper.GetSingleAttributeOrDefault<RequiresGlobalFeatureAttribute>(controllerType);
return attribute == null || GlobalFeatureManager.Instance.IsEnabled(attribute.GetFeatureName());
using (AbpCrossCuttingConcerns.Applying(context.Controller, AbpCrossCuttingConcerns.GlobalFeatureChecking))
{
await next();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using System;
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Aspects;
using Volo.Abp.DependencyInjection;
using Volo.Abp.GlobalFeatures;
using Volo.Abp.Reflection;

namespace Volo.Abp.AspNetCore.Mvc.GlobalFeatures
{
Expand All @@ -26,21 +26,18 @@ public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext contex
return;
}

if (!IsGlobalFeatureEnabled(context.HandlerInstance.GetType(), out var attribute))
if (!GlobalFeatureHelper.IsGlobalFeatureEnabled(context.HandlerInstance.GetType(), out var attribute))
{
var logger = context.GetService<ILogger<GlobalFeatureActionFilter>>(NullLogger<GlobalFeatureActionFilter>.Instance);
logger.LogWarning($"The '{context.HandlerInstance.GetType().FullName}' page needs to enable '{attribute.Name}' feature.");
context.Result = new NotFoundResult();
return;
}

await next();
}

protected virtual bool IsGlobalFeatureEnabled(Type controllerType, out RequiresGlobalFeatureAttribute attribute)
{
attribute = ReflectionHelper.GetSingleAttributeOrDefault<RequiresGlobalFeatureAttribute>(controllerType);
return attribute == null || GlobalFeatureManager.Instance.IsEnabled(attribute.GetFeatureName());
using (AbpCrossCuttingConcerns.Applying(context.HandlerInstance, AbpCrossCuttingConcerns.GlobalFeatureChecking))
{
await next();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public static class AbpCrossCuttingConcerns
public const string Auditing = "AbpAuditing";
public const string UnitOfWork = "AbpUnitOfWork";
public const string FeatureChecking = "AbpFeatureChecking";
public const string GlobalFeatureChecking = "AbpGlobalFeatureChecking";

public static void AddApplied(object obj, params string[] concerns)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<ProjectReference Include="..\Volo.Abp.Ddd.Application.Contracts\Volo.Abp.Ddd.Application.Contracts.csproj" />
<ProjectReference Include="..\Volo.Abp.Ddd.Domain\Volo.Abp.Ddd.Domain.csproj" />
<ProjectReference Include="..\Volo.Abp.Features\Volo.Abp.Features.csproj" />
<ProjectReference Include="..\Volo.Abp.GlobalFeatures\Volo.Abp.GlobalFeatures.csproj" />
<ProjectReference Include="..\Volo.Abp.Http.Abstractions\Volo.Abp.Http.Abstractions.csproj" />
<ProjectReference Include="..\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
<ProjectReference Include="..\Volo.Abp.ObjectMapping\Volo.Abp.ObjectMapping.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Volo.Abp.Authorization;
using Volo.Abp.Domain;
using Volo.Abp.Features;
using Volo.Abp.GlobalFeatures;
using Volo.Abp.Http;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Modularity;
Expand All @@ -23,7 +24,8 @@ namespace Volo.Abp.Application
typeof(AbpAuthorizationModule),
typeof(AbpHttpAbstractionsModule),
typeof(AbpSettingsModule),
typeof(AbpFeaturesModule)
typeof(AbpFeaturesModule),
typeof(AbpGlobalFeaturesModule)
)]
public class AbpDddApplicationModule : AbpModule
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Volo.Abp.Authorization;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
using Volo.Abp.GlobalFeatures;
using Volo.Abp.Guids;
using Volo.Abp.Linq;
using Volo.Abp.Localization;
Expand All @@ -31,6 +32,7 @@ public abstract class ApplicationService :
IValidationEnabled,
IUnitOfWorkEnabled,
IAuditingEnabled,
IGlobalFeatureCheckingEnabled,
ITransientDependency
{
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@
<RootNamespace />
</PropertyGroup>

<ItemGroup>
<None Remove="Volo\Abp\GlobalFeatures\Localization\*.json" />
<EmbeddedResource Include="Volo\Abp\GlobalFeatures\Localization\*.json" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" />
<ProjectReference Include="..\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
<ProjectReference Include="..\Volo.Abp.VirtualFileSystem\Volo.Abp.VirtualFileSystem.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Volo.Abp.GlobalFeatures
{
public class AbpGlobalFeatureErrorCodes
{
public const string GlobalFeatureIsNotEnabled = "Volo.GlobalFeature:010001";
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
@@ -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));
});
}
}
}
Original file line number Diff line number Diff line change
@@ -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());
}
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Volo.Abp.GlobalFeatures
{
public interface IGlobalFeatureCheckingEnabled
{

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Volo.Abp.Localization;

namespace Volo.Abp.GlobalFeatures.Localization
{
[LocalizationResourceName("AbpGlobalFeature")]
public class AbpGlobalFeatureResource
{

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"culture": "en",
"texts": {
"Volo.GlobalFeature:010001": "The '{ServiceName}' service needs to enable '{GlobalFeatureName}' feature."
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"culture": "tr",
"texts": {
"Volo.GlobalFeature:010001": "'{ServiceName}' hizmetinin '{GlobalFeatureName}' özelliğini etkinleştirmesi gerekiyor."
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"culture": "zh-Hans",
"texts": {
"Volo.GlobalFeature:010001": "'{ServiceName}'服务需要启用'{GlobalFeatureName}'功能."
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"culture": "zh-Hant",
"texts": {
"Volo.GlobalFeature:010001": "'{ServiceName}'服務需要啟用'{GlobalFeatureName}'功能."
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Ddd.Application\Volo.Abp.Ddd.Application.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.GlobalFeatures\Volo.Abp.GlobalFeatures.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.ExceptionHandling\Volo.Abp.ExceptionHandling.csproj" />
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -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 comments on commit f6ab71d

Please sign in to comment.