mirror of https://github.com/abpframework/abp.git
158 changed files with 1460 additions and 312 deletions
@ -0,0 +1,72 @@ |
|||||
|
# Use Deepl to translate localization files |
||||
|
|
||||
|
Translating localized text during the development of ABP modules is a boring job. For this reason, we have added the `translate` command to the CLI tool to translate the localization files, but it still requires manual translation of texts by the developer. |
||||
|
|
||||
|
Now, we introduce a new way to translate the target language, which is to use the [Deepl](https://www.deepl.com/translator) translation service to translate the target language. |
||||
|
|
||||
|
You can use the `translate --online` command in your module directory to translate the target language. |
||||
|
|
||||
|
For example, if you have added all `en` localization texts to your module, and you want to translate them to `zh-Hans`, you can run the following command: |
||||
|
|
||||
|
``` |
||||
|
abp translate -r en -c zh-Hans --online --deepl-auth-key your_auth_key |
||||
|
``` |
||||
|
|
||||
|
* `-r` parameter is used to specify the source language. It is usually a localized file that you have created. |
||||
|
* `-c` parameter is used to specify the target language. It is usually a language that you want to translate. |
||||
|
* `--online` parameter is used to indicate that the translation is performed from the Deepl service. |
||||
|
* `--deepl-auth-key` parameter is the API key of your Deepl account. You can get it from [here](https://support.deepl.com/hc/en-us/articles/360020695820-Authentication-Key). |
||||
|
|
||||
|
|
||||
|
The output of the above command is as follows: |
||||
|
|
||||
|
``` |
||||
|
ABP CLI 8.0.0 |
||||
|
Abp translate online... |
||||
|
Target culture: zh-Hans |
||||
|
Reference culture: en |
||||
|
Create translation: Settings => 设置 |
||||
|
Create translation: SuccessfullySaved => 成功保存 |
||||
|
Create translation: Permission:SettingManagement => 设置管理 |
||||
|
Create translation: Permission:Emailing => 发送电子邮件 |
||||
|
Create translation: Permission:EmailingTest => 电子邮件测试 |
||||
|
Create translation: Permission:TimeZone => 时区 |
||||
|
Create translation: SendTestEmail => 发送测试电子邮件 |
||||
|
Create translation: SenderEmailAddress => 发件人电子邮件地址 |
||||
|
Create translation: TargetEmailAddress => 目标电子邮件地址 |
||||
|
Create translation: Subject => 主题 |
||||
|
Create translation: Body => 正文 |
||||
|
Create translation: TestEmailSubject => 测试电子邮件 {0} |
||||
|
Create translation: TestEmailBody => 在此测试电子邮件正文信息 |
||||
|
Create translation: SuccessfullySent => 成功发送 |
||||
|
Create translation: Send => 发送 |
||||
|
Create translation: Menu:Emailing => 发送电子邮件 |
||||
|
Create translation: Menu:TimeZone => 时区 |
||||
|
Create translation: DisplayName:Timezone => 时区 |
||||
|
Create translation: TimezoneHelpText => 此设置用于应用程序范围或基于租户的设置。 |
||||
|
Create translation: SmtpHost => 主机 |
||||
|
Create translation: SmtpPort => 端口 |
||||
|
Create translation: SmtpUserName => 用户名 |
||||
|
Create translation: SmtpPassword => 密码 |
||||
|
Create translation: SmtpDomain => 域名 |
||||
|
Create translation: SmtpEnableSsl => 启用 ssl |
||||
|
Create translation: SmtpUseDefaultCredentials => 使用默认凭据 |
||||
|
Create translation: DefaultFromAddress => 默认地址 |
||||
|
Create translation: DefaultFromDisplayName => 显示名称的默认值 |
||||
|
Create translation: Feature:SettingManagementGroup => 设置管理 |
||||
|
Create translation: Feature:SettingManagementEnable => 启用设置管理 |
||||
|
Create translation: Feature:SettingManagementEnableDescription => 在应用程序中启用设置管理系统。 |
||||
|
Create translation: Feature:AllowChangingEmailSettings => 允许更改电子邮件设置。 |
||||
|
Create translation: Feature:AllowChangingEmailSettingsDescription => 允许更改电子邮件设置。 |
||||
|
Write translation json to setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/zh-Hans.json. |
||||
|
``` |
||||
|
|
||||
|
The generated `zh-Hans.json` as follow: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
In this example, It only translates one `en.json` to `zh-Hans.json`, but if there are multiple `en.json` files in the module, it will translate all `en.json` files to `zh-Hans.json`. |
||||
|
|
||||
|
Of course, the translation is not always correct, you can update the translation in the generated `zh-Hans.json` files. |
||||
|
|
||||
|
Enjoy it! |
||||
|
After Width: | Height: | Size: 456 KiB |
@ -0,0 +1,85 @@ |
|||||
|
# ABP Version 8.1 Migration Guide |
||||
|
|
||||
|
This document is a guide for upgrading ABP v8.0 solutions to ABP v8.1. There are some changes in this version that may affect your applications, please read it carefully and apply the necessary changes to your application. |
||||
|
|
||||
|
## Added `NormalizedName` property to `Tenant` |
||||
|
|
||||
|
The `Tenant` entity has a new property called `NormalizedName`. It is used to find/cache a tenant by its name in a case-insensitive way. |
||||
|
This property is automatically set when a tenant is created or updated. It gets the normalized name of the tenant name by `UpperInvariantTenantNormalizer(ITenantNormalizer)` service. You can implement this service to change the normalization logic. |
||||
|
|
||||
|
### `ITenantStore` |
||||
|
|
||||
|
The `ITenantStore` will use the `NormalizedName` parameter to get tenants, Please use the `ITenantNormalizer` to normalize the tenant name before calling the `ITenantStore` methods. |
||||
|
|
||||
|
### Update `NormalizedName` in `appsettings.json` |
||||
|
|
||||
|
If your tenants defined in the `appsettings.json` file, you should add the `NormalizedName` property to your tenants. |
||||
|
|
||||
|
````json |
||||
|
"Tenants": [ |
||||
|
{ |
||||
|
"Id": "446a5211-3d72-4339-9adc-845151f8ada0", |
||||
|
"Name": "tenant1", |
||||
|
"NormalizedName": "TENANT1" // <-- Add this property |
||||
|
}, |
||||
|
{ |
||||
|
"Id": "25388015-ef1c-4355-9c18-f6b6ddbaf89d", |
||||
|
"Name": "tenant2", |
||||
|
"NormalizedName": "TENANT2", // <-- Add this property |
||||
|
"ConnectionStrings": { |
||||
|
"Default": "...tenant2's db connection string here..." |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
```` |
||||
|
|
||||
|
### Update `NormalizedName` in the database |
||||
|
|
||||
|
Please add a sql script to your migration to set the `NormalizedName` property of the existing tenants. You can use the following script: |
||||
|
|
||||
|
> This script is for the SQL Server database. You can change it for your database. |
||||
|
|
||||
|
> The table name `SaasTenants` is used for ABP commercial Saas module. `AbpTenants` is for the ABP open-source Tenant Management module. |
||||
|
|
||||
|
```sql |
||||
|
UPDATE SaasTenants SET NormalizedName = UPPER(Name) WHERE NormalizedName IS NULL OR NormalizedName = '' |
||||
|
``` |
||||
|
|
||||
|
```csharp |
||||
|
/// <inheritdoc /> |
||||
|
public partial class Add_NormalizedName : Migration |
||||
|
{ |
||||
|
/// <inheritdoc /> |
||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.AddColumn<string>( |
||||
|
name: "NormalizedName", |
||||
|
table: "SaasTenants", |
||||
|
type: "nvarchar(64)", |
||||
|
nullable: false, |
||||
|
defaultValue: ""); |
||||
|
|
||||
|
migrationBuilder.Sql("UPDATE SaasTenants SET NormalizedName = UPPER(Name) WHERE NormalizedName IS NULL OR NormalizedName = ''"); |
||||
|
|
||||
|
migrationBuilder.CreateIndex( |
||||
|
name: "IX_SaasTenants_NormalizedName", |
||||
|
table: "SaasTenants", |
||||
|
column: "NormalizedName"); |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc /> |
||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.DropIndex( |
||||
|
name: "IX_SaasTenants_NormalizedName", |
||||
|
table: "SaasTenants"); |
||||
|
|
||||
|
migrationBuilder.DropColumn( |
||||
|
name: "NormalizedName", |
||||
|
table: "SaasTenants"); |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
See https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/managing?tabs=dotnet-core-cli#adding-raw-sql to learn how to add raw SQL to migrations. |
||||
|
|
||||
@ -0,0 +1,31 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.Abstractions; |
||||
|
using Microsoft.AspNetCore.Mvc.Controllers; |
||||
|
using Volo.Abp.AspNetCore.Filters; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationModels; |
||||
|
|
||||
|
public class AbpMvcActionDescriptorProvider : IActionDescriptorProvider |
||||
|
{ |
||||
|
public virtual int Order => -1000 + 10; |
||||
|
|
||||
|
public virtual void OnProvidersExecuting(ActionDescriptorProviderContext context) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public virtual void OnProvidersExecuted(ActionDescriptorProviderContext context) |
||||
|
{ |
||||
|
foreach (var action in context.Results.Where(x => x is ControllerActionDescriptor).Cast<ControllerActionDescriptor>()) |
||||
|
{ |
||||
|
var disableAbpFeaturesAttribute = action.ControllerTypeInfo.GetCustomAttribute<DisableAbpFeaturesAttribute>(true); |
||||
|
if (disableAbpFeaturesAttribute != null && disableAbpFeaturesAttribute.DisableMvcFilters) |
||||
|
{ |
||||
|
action.FilterDescriptors.RemoveAll(x => x.Filter is ServiceFilterAttribute serviceFilterAttribute && |
||||
|
typeof(IAbpFilter).IsAssignableFrom(serviceFilterAttribute.ServiceType)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Filters; |
||||
|
|
||||
|
public interface IAbpFilter |
||||
|
{ |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System.Reflection; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Http; |
||||
|
using Microsoft.AspNetCore.Mvc.Controllers; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Middleware; |
||||
|
|
||||
|
public abstract class AbpMiddlewareBase : IMiddleware |
||||
|
{ |
||||
|
protected Task<bool> ShouldSkipAsync(HttpContext context, RequestDelegate next) |
||||
|
{ |
||||
|
var endpoint = context.GetEndpoint(); |
||||
|
var controllerActionDescriptor = endpoint?.Metadata.GetMetadata<ControllerActionDescriptor>(); |
||||
|
var disableAbpFeaturesAttribute = controllerActionDescriptor?.ControllerTypeInfo.GetCustomAttribute<DisableAbpFeaturesAttribute>(); |
||||
|
return Task.FromResult(disableAbpFeaturesAttribute != null && disableAbpFeaturesAttribute.DisableMiddleware); |
||||
|
} |
||||
|
|
||||
|
public abstract Task InvokeAsync(HttpContext context, RequestDelegate next); |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp; |
||||
|
|
||||
|
[AttributeUsage(AttributeTargets.Class)] |
||||
|
public class DisableAbpFeaturesAttribute : Attribute |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The framework will not register any interceptors for the class.
|
||||
|
/// This will cause the all features that depend on interceptors to not work.
|
||||
|
/// </summary>
|
||||
|
public bool DisableInterceptors { get; set; } = true; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The framework middleware will skip the class.
|
||||
|
/// This will cause the all features that depend on middleware to not work.
|
||||
|
/// </summary>
|
||||
|
public bool DisableMiddleware { get; set; } = true; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The framework will not remove all built-in filters for the class.
|
||||
|
/// This will cause the all features that depend on filters to not work.
|
||||
|
/// </summary>
|
||||
|
public bool DisableMvcFilters { get; set; } = true; |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.Features; |
||||
|
|
||||
|
public class FeatureValueProviderManager : IFeatureValueProviderManager, ISingletonDependency |
||||
|
{ |
||||
|
public IReadOnlyList<IFeatureValueProvider> ValueProviders => _lazyProviders.Value; |
||||
|
private readonly Lazy<List<IFeatureValueProvider>> _lazyProviders; |
||||
|
|
||||
|
protected AbpFeatureOptions Options { get; } |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
public FeatureValueProviderManager( |
||||
|
IServiceProvider serviceProvider, |
||||
|
IOptions<AbpFeatureOptions> options) |
||||
|
{ |
||||
|
Options = options.Value; |
||||
|
ServiceProvider = serviceProvider; |
||||
|
|
||||
|
_lazyProviders = new Lazy<List<IFeatureValueProvider>>(GetProviders, true); |
||||
|
} |
||||
|
|
||||
|
protected virtual List<IFeatureValueProvider> GetProviders() |
||||
|
{ |
||||
|
var providers = Options |
||||
|
.ValueProviders |
||||
|
.Select(type => (ServiceProvider.GetRequiredService(type) as IFeatureValueProvider)!) |
||||
|
.ToList(); |
||||
|
|
||||
|
var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1); |
||||
|
if(multipleProviders != null) |
||||
|
{ |
||||
|
throw new AbpException($"Duplicate feature value provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}"); |
||||
|
} |
||||
|
|
||||
|
return providers; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.Features; |
||||
|
|
||||
|
public interface IFeatureValueProviderManager |
||||
|
{ |
||||
|
IReadOnlyList<IFeatureValueProvider> ValueProviders { get; } |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
public interface ITenantNormalizer |
||||
|
{ |
||||
|
string? NormalizeName(string? name); |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
public class UpperInvariantTenantNormalizer : ITenantNormalizer, ITransientDependency |
||||
|
{ |
||||
|
public virtual string? NormalizeName(string? name) |
||||
|
{ |
||||
|
return name?.Normalize().ToUpperInvariant(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,74 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Http; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.Controllers; |
||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.AspNetCore.Mvc.Auditing; |
||||
|
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; |
||||
|
using Volo.Abp.AspNetCore.Mvc.Features; |
||||
|
using Volo.Abp.AspNetCore.Mvc.GlobalFeatures; |
||||
|
using Volo.Abp.AspNetCore.Mvc.Response; |
||||
|
using Volo.Abp.AspNetCore.Mvc.Uow; |
||||
|
using Volo.Abp.AspNetCore.Mvc.Validation; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.Filters; |
||||
|
|
||||
|
[Route("api/enabled-features-test")] |
||||
|
public class EnabledAbpFeaturesController : AbpController, IRemoteService |
||||
|
{ |
||||
|
[HttpGet] |
||||
|
public Task<List<string>> GetAsync() |
||||
|
{ |
||||
|
var filters = HttpContext.GetEndpoint().Metadata.GetMetadata<ControllerActionDescriptor>() |
||||
|
.FilterDescriptors.Where(x => x.Filter is ServiceFilterAttribute) |
||||
|
.Select(x => x.Filter.As<ServiceFilterAttribute>().ServiceType.FullName).ToList(); |
||||
|
|
||||
|
return Task.FromResult(filters); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Route("api/disabled-features-test")] |
||||
|
[DisableAbpFeatures] |
||||
|
public class DisabledAbpFeaturesController : AbpController, IRemoteService |
||||
|
{ |
||||
|
[HttpGet] |
||||
|
public Task<List<string>> GetAsync() |
||||
|
{ |
||||
|
var filters = HttpContext.GetEndpoint().Metadata.GetMetadata<ControllerActionDescriptor>() |
||||
|
.FilterDescriptors.Where(x => x.Filter is ServiceFilterAttribute) |
||||
|
.Select(x => x.Filter.As<ServiceFilterAttribute>().ServiceType.FullName).ToList(); |
||||
|
|
||||
|
return Task.FromResult(filters); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class MvcDisableAbpFeaturesAttribute_Tests : AspNetCoreMvcTestBase |
||||
|
{ |
||||
|
[Fact] |
||||
|
public async Task Should_Disable_MVC_Filters() |
||||
|
{ |
||||
|
var filters = await GetResponseAsObjectAsync<List<string>>("/api/enabled-features-test"); |
||||
|
filters.ShouldContain(typeof(GlobalFeatureActionFilter).FullName); |
||||
|
filters.ShouldContain(typeof(AbpAuditActionFilter).FullName); |
||||
|
filters.ShouldContain(typeof(AbpNoContentActionFilter).FullName); |
||||
|
filters.ShouldContain(typeof(AbpFeatureActionFilter).FullName); |
||||
|
filters.ShouldContain(typeof(AbpValidationActionFilter).FullName); |
||||
|
filters.ShouldContain(typeof(AbpUowActionFilter).FullName); |
||||
|
filters.ShouldContain(typeof(AbpExceptionFilter).FullName); |
||||
|
|
||||
|
filters = await GetResponseAsObjectAsync<List<string>>("/api/disabled-features-test"); |
||||
|
filters.ShouldNotContain(typeof(GlobalFeatureActionFilter).FullName); |
||||
|
filters.ShouldNotContain(typeof(AbpAuditActionFilter).FullName); |
||||
|
filters.ShouldNotContain(typeof(AbpNoContentActionFilter).FullName); |
||||
|
filters.ShouldNotContain(typeof(AbpFeatureActionFilter).FullName); |
||||
|
filters.ShouldNotContain(typeof(AbpValidationActionFilter).FullName); |
||||
|
filters.ShouldNotContain(typeof(AbpUowActionFilter).FullName); |
||||
|
filters.ShouldNotContain(typeof(AbpExceptionFilter).FullName); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,59 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Authorization; |
||||
|
using Volo.Abp.Authorization.Permissions; |
||||
|
using Volo.Abp.Authorization.TestServices; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp; |
||||
|
|
||||
|
public class PermissionValueProviderManager_Tests: AuthorizationTestBase |
||||
|
{ |
||||
|
private readonly IPermissionValueProviderManager _permissionValueProviderManager; |
||||
|
|
||||
|
public PermissionValueProviderManager_Tests() |
||||
|
{ |
||||
|
_permissionValueProviderManager = GetRequiredService<IPermissionValueProviderManager>(); |
||||
|
} |
||||
|
|
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.Services.Configure<AbpPermissionOptions>(permissionOptions => |
||||
|
{ |
||||
|
permissionOptions.ValueProviders.Add<TestDuplicatePermissionValueProvider>(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected() |
||||
|
{ |
||||
|
var exception = Assert.Throws<AbpException>(() => |
||||
|
{ |
||||
|
var providers = _permissionValueProviderManager.ValueProviders; |
||||
|
}); |
||||
|
|
||||
|
exception.Message.ShouldBe($"Duplicate permission value provider name detected: TestPermissionValueProvider1. Providers:{Environment.NewLine}{typeof(TestDuplicatePermissionValueProvider).FullName}{Environment.NewLine}{typeof(TestPermissionValueProvider1).FullName}"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class TestDuplicatePermissionValueProvider : PermissionValueProvider |
||||
|
{ |
||||
|
public TestDuplicatePermissionValueProvider(IPermissionStore permissionStore) : base(permissionStore) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override string Name => "TestPermissionValueProvider1"; |
||||
|
|
||||
|
public override Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
public override Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Volo.Abp.DynamicProxy; |
||||
|
|
||||
|
public class AlwaysExceptionAsyncInterceptor : AbpInterceptor |
||||
|
{ |
||||
|
public override Task InterceptAsync(IAbpMethodInvocation invocation) |
||||
|
{ |
||||
|
throw new AbpException("This interceptor should not be executed!"); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.TestBase.Logging; |
||||
|
|
||||
|
namespace Volo.Abp.DynamicProxy; |
||||
|
|
||||
|
[DisableAbpFeatures] |
||||
|
public class DisableInterceptionTargetClass : ICanLogOnObject |
||||
|
{ |
||||
|
public List<string> Logs { get; } = new List<string>(); |
||||
|
|
||||
|
public virtual void DoIt() |
||||
|
{ |
||||
|
Logs.Add("ExecutingDoIt"); |
||||
|
} |
||||
|
|
||||
|
public virtual int GetValue() |
||||
|
{ |
||||
|
Logs.Add("ExecutingGetValue"); |
||||
|
return 42; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<int> GetValueAsync() |
||||
|
{ |
||||
|
Logs.Add("EnterGetValueAsync"); |
||||
|
await Task.Delay(5); |
||||
|
Logs.Add("MiddleGetValueAsync"); |
||||
|
await Task.Delay(5); |
||||
|
Logs.Add("ExitGetValueAsync"); |
||||
|
return 42; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task DoItAsync() |
||||
|
{ |
||||
|
Logs.Add("EnterDoItAsync"); |
||||
|
await Task.Delay(5); |
||||
|
Logs.Add("MiddleDoItAsync"); |
||||
|
await Task.Delay(5); |
||||
|
Logs.Add("ExitDoItAsync"); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Shouldly; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.Features; |
||||
|
|
||||
|
public class FeatureValueProviderManager_Tests : FeatureTestBase |
||||
|
{ |
||||
|
private readonly IFeatureValueProviderManager _featureValueProviderManager; |
||||
|
|
||||
|
public FeatureValueProviderManager_Tests() |
||||
|
{ |
||||
|
_featureValueProviderManager = GetRequiredService<IFeatureValueProviderManager>(); |
||||
|
} |
||||
|
|
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.Services.Configure<AbpFeatureOptions>(permissionOptions => |
||||
|
{ |
||||
|
permissionOptions.ValueProviders.Add<TestDuplicateFeatureValueProvider>(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected() |
||||
|
{ |
||||
|
var exception = Assert.Throws<AbpException>(() => |
||||
|
{ |
||||
|
var providers = _featureValueProviderManager.ValueProviders; |
||||
|
}); |
||||
|
|
||||
|
exception.Message.ShouldBe($"Duplicate feature value provider name detected: {TestDuplicateFeatureValueProvider.ProviderName}. Providers:{Environment.NewLine}{typeof(TestDuplicateFeatureValueProvider).FullName}{Environment.NewLine}{typeof(DefaultValueFeatureValueProvider).FullName}"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class TestDuplicateFeatureValueProvider : FeatureValueProvider |
||||
|
{ |
||||
|
public const string ProviderName = "D"; |
||||
|
|
||||
|
public override string Name => ProviderName; |
||||
|
|
||||
|
public TestDuplicateFeatureValueProvider(IFeatureStore settingStore) |
||||
|
: base(settingStore) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public override Task<string> GetOrNullAsync(FeatureDefinition setting) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,62 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Testing; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.Settings; |
||||
|
|
||||
|
public class SettingValueProviderManager_Tests: AbpIntegratedTest<AbpSettingsTestModule> |
||||
|
{ |
||||
|
private readonly ISettingValueProviderManager _settingValueProviderManager; |
||||
|
|
||||
|
public SettingValueProviderManager_Tests() |
||||
|
{ |
||||
|
_settingValueProviderManager = GetRequiredService<ISettingValueProviderManager>(); |
||||
|
} |
||||
|
|
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
options.Services.Configure<AbpSettingOptions>(settingOptions => |
||||
|
{ |
||||
|
settingOptions.ValueProviders.Add<TestDuplicateSettingValueProvider>(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected() |
||||
|
{ |
||||
|
var exception = Assert.Throws<AbpException>(() => |
||||
|
{ |
||||
|
var providers = _settingValueProviderManager.Providers; |
||||
|
}); |
||||
|
|
||||
|
exception.Message.ShouldBe($"Duplicate setting value provider name detected: {TestDuplicateSettingValueProvider.ProviderName}. Providers:{Environment.NewLine}{typeof(TestDuplicateSettingValueProvider).FullName}{Environment.NewLine}{typeof(TestSettingValueProvider).FullName}"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class TestDuplicateSettingValueProvider : ISettingValueProvider, ITransientDependency |
||||
|
{ |
||||
|
public const string ProviderName = "Test"; |
||||
|
|
||||
|
|
||||
|
public string Name => ProviderName; |
||||
|
|
||||
|
public TestDuplicateSettingValueProvider() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public Task<string> GetOrNullAsync(SettingDefinition setting) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
public Task<List<SettingValue>> GetAllAsync(SettingDefinition[] settings) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue