Localize exception messages in AbpFeaturesModule.

Resolve #1119
pull/6509/head
maliming 5 years ago
parent 90a7039d50
commit 68365f9a46

@ -62,12 +62,6 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling
return CreateEntityNotFoundError(exception as EntityNotFoundException);
}
if (exception is AbpAuthorizationException)
{
var authorizationException = exception as AbpAuthorizationException;
return new RemoteServiceErrorInfo(authorizationException.Message);
}
var errorInfo = new RemoteServiceErrorInfo();
if (exception is IUserFriendlyException)

@ -15,7 +15,12 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Localization.Abstractions\Volo.Abp.Localization.Abstractions.csproj" />
<None Remove="Volo\Abp\Features\Localization\*.json" />
<EmbeddedResource Include="Volo\Abp\Features\Localization\*.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
<ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" />
<ProjectReference Include="..\Volo.Abp.Validation\Volo.Abp.Validation.csproj" />
</ItemGroup>

@ -0,0 +1,11 @@
namespace Volo.Abp.Features
{
public static class AbpFeatureErrorCodes
{
public const string FeatureIsNotEnabled = "Volo.Feature:010001";
public const string AllOfTheseFeaturesMustBeEnabled = "Volo.Feature:010002";
public const string AtLeastOneOfTheseFeaturesMustBeEnabled = "Volo.Feature:010003";
}
}

@ -1,15 +1,18 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using Volo.Abp.Features.Localization;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Validation;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Features
{
[DependsOn(
typeof(AbpLocalizationAbstractionsModule),
typeof(AbpLocalizationModule),
typeof(AbpMultiTenancyModule),
typeof(AbpValidationModule)
)]
@ -29,6 +32,23 @@ namespace Volo.Abp.Features
options.ValueProviders.Add<EditionFeatureValueProvider>();
options.ValueProviders.Add<TenantFeatureValueProvider>();
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpFeatureResource>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<AbpFeatureResource>("en")
.AddVirtualJson("/Volo/Abp/Features/Localization");
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace("Volo.Feature", typeof(AbpFeatureResource));
});
}
private static void AutoAddDefinitionProviders(IServiceCollection services)

@ -9,8 +9,8 @@ namespace Volo.Abp.Features
public static class FeatureCheckerExtensions
{
public static async Task<T> GetAsync<T>(
[NotNull] this IFeatureChecker featureChecker,
[NotNull] string name,
[NotNull] this IFeatureChecker featureChecker,
[NotNull] string name,
T defaultValue = default)
where T : struct
{
@ -56,10 +56,11 @@ namespace Volo.Abp.Features
{
if (!(await featureChecker.IsEnabledAsync(featureName)))
{
throw new AbpAuthorizationException("Feature is not enabled: " + featureName);
throw new AbpAuthorizationException(code: AbpFeatureErrorCodes.FeatureIsNotEnabled).WithData(
"FeatureName", featureName);
}
}
public static async Task CheckEnabledAsync(this IFeatureChecker featureChecker, bool requiresAll, params string[] featureNames)
{
if (featureNames.IsNullOrEmpty())
@ -73,10 +74,8 @@ namespace Volo.Abp.Features
{
if (!(await featureChecker.IsEnabledAsync(featureName)))
{
throw new AbpAuthorizationException(
"Required features are not enabled. All of these features must be enabled: " +
string.Join(", ", featureNames)
);
throw new AbpAuthorizationException(code: AbpFeatureErrorCodes.AllOfTheseFeaturesMustBeEnabled)
.WithData("FeatureNames", string.Join(", ", featureNames));
}
}
}
@ -90,11 +89,9 @@ namespace Volo.Abp.Features
}
}
throw new AbpAuthorizationException(
"Required features are not enabled. At least one of these features must be enabled: " +
string.Join(", ", featureNames)
);
throw new AbpAuthorizationException(code: AbpFeatureErrorCodes.AtLeastOneOfTheseFeaturesMustBeEnabled)
.WithData("FeatureNames", string.Join(", ", featureNames));
}
}
}
}
}

@ -0,0 +1,10 @@
using Volo.Abp.Localization;
namespace Volo.Abp.Features.Localization
{
[LocalizationResourceName("AbpFeature")]
public class AbpFeatureResource
{
}
}

@ -0,0 +1,8 @@
{
"culture": "en",
"texts": {
"Volo.Feature:010001": "Feature is not enabled: {FeatureName}",
"Volo.Feature:010002": "Required features are not enabled. All of these features must be enabled: {FeatureNames}",
"Volo.Feature:010003": "Required features are not enabled. At least one of these features must be enabled: {FeatureNames}"
}
}

@ -0,0 +1,8 @@
{
"culture": "tr",
"texts": {
"Volo.Feature:010001": "Özellik etkinleştirilmedi: {FeatureName}",
"Volo.Feature:010002": "Gerekli özellikler etkinleştirilmedi. Bu özelliklerin tümü etkinleştirilmelidir: {FeatureNames}",
"Volo.Feature:010003": "Gerekli özellikler etkinleştirilmedi. Bu özelliklerden en az birinin etkinleştirilmesi gerekir: {FeatureNames}"
}
}

@ -0,0 +1,8 @@
{
"culture": "zh-Hans",
"texts": {
"Volo.Feature:010001": "功能未启用: {FeatureName}",
"Volo.Feature:010002": "必要的功能未启用. 这些功能需要启用: {FeatureNames}",
"Volo.Feature:010003": "必要的功能未启用. 需要启用这些功能中的一项:{FeatureNames}"
}
}

@ -1,6 +1,7 @@
using System;
using System.Runtime.Serialization;
using Microsoft.Extensions.Logging;
using Volo.Abp.ExceptionHandling;
using Volo.Abp.Logging;
namespace Volo.Abp.Authorization
@ -9,7 +10,7 @@ namespace Volo.Abp.Authorization
/// This exception is thrown on an unauthorized request.
/// </summary>
[Serializable]
public class AbpAuthorizationException : AbpException, IHasLogLevel
public class AbpAuthorizationException : AbpException, IHasLogLevel, IHasErrorCode
{
/// <summary>
/// Severity of the exception.
@ -17,6 +18,11 @@ namespace Volo.Abp.Authorization
/// </summary>
public LogLevel LogLevel { get; set; }
/// <summary>
/// Error code.
/// </summary>
public string Code { get; }
/// <summary>
/// Creates a new <see cref="AbpAuthorizationException"/> object.
/// </summary>
@ -54,5 +60,24 @@ namespace Volo.Abp.Authorization
{
LogLevel = LogLevel.Warning;
}
/// <summary>
/// Creates a new <see cref="AbpAuthorizationException"/> object.
/// </summary>
/// <param name="message">Exception message</param>
/// <param name="code">Exception code</param>
/// <param name="innerException">Inner exception</param>
public AbpAuthorizationException(string message = null, string code = null, Exception innerException = null)
: base(message, innerException)
{
Code = code;
LogLevel = LogLevel.Warning;
}
public AbpAuthorizationException WithData(string name, object value)
{
Data[name] = value;
return this;
}
}
}
}

@ -9,6 +9,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.ExceptionHandling\Volo.Abp.ExceptionHandling.csproj" />
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Features\Volo.Abp.Features.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />

@ -1,10 +1,12 @@
using Volo.Abp.Autofac;
using Volo.Abp.ExceptionHandling;
using Volo.Abp.Modularity;
namespace Volo.Abp.Features
{
[DependsOn(
typeof(AbpFeaturesModule),
typeof(AbpExceptionHandlingModule),
typeof(AbpTestBaseModule),
typeof(AbpAutofacModule)
)]
@ -12,7 +14,7 @@ namespace Volo.Abp.Features
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
}
}

@ -0,0 +1,60 @@
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.Authorization;
using Volo.Abp.Localization;
using Xunit;
namespace Volo.Abp.Features
{
public class FeatureCheckerExtensions_Tests : FeatureTestBase
{
private readonly IFeatureChecker _featureChecker;
private readonly IExceptionToErrorInfoConverter _exceptionToErrorInfoConverter;
public FeatureCheckerExtensions_Tests()
{
_featureChecker = GetRequiredService<IFeatureChecker>();
_exceptionToErrorInfoConverter = GetRequiredService<IExceptionToErrorInfoConverter>();
}
[Fact]
public async Task CheckEnabledAsync()
{
using (CultureHelper.Use("zh-Hans"))
{
var ex = await Assert.ThrowsAsync<AbpAuthorizationException>(async () =>
await _featureChecker.CheckEnabledAsync("BooleanTestFeature1"));
var errorInfo = _exceptionToErrorInfoConverter.Convert(ex, false);
errorInfo.Message.ShouldBe("功能未启用: BooleanTestFeature1");
}
}
[Fact]
public async Task CheckEnabled_RequiresAll()
{
using (CultureHelper.Use("zh-Hans"))
{
var ex = await Assert.ThrowsAsync<AbpAuthorizationException>(async () =>
await _featureChecker.CheckEnabledAsync(true, "BooleanTestFeature1", "BooleanTestFeature2"));
var errorInfo = _exceptionToErrorInfoConverter.Convert(ex, false);
errorInfo.Message.ShouldBe("必要的功能未启用. 这些功能需要启用: BooleanTestFeature1, BooleanTestFeature2");
}
}
[Fact]
public async Task CheckEnabled_Not_RequiresAll()
{
using (CultureHelper.Use("zh-Hans"))
{
var ex = await Assert.ThrowsAsync<AbpAuthorizationException>(async () =>
await _featureChecker.CheckEnabledAsync(false, "BooleanTestFeature1", "BooleanTestFeature2"));
var errorInfo = _exceptionToErrorInfoConverter.Convert(ex, false);
errorInfo.Message.ShouldBe("必要的功能未启用. 需要启用这些功能中的一项BooleanTestFeature1, BooleanTestFeature2");
}
}
}
}
Loading…
Cancel
Save