Browse Source

Concurrently retrieving configuration/localization info in `MvcCachedApplicationConfigurationClient`.

pull/24838/head
maliming 5 months ago
parent
commit
a0aa7469df
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 1
      framework/Volo.Abp.slnx
  2. 32
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs
  3. 17
      framework/test/Volo.Abp.AspNetCore.Mvc.Client.Tests/Volo.Abp.AspNetCore.Mvc.Client.Tests.csproj
  4. 11
      framework/test/Volo.Abp.AspNetCore.Mvc.Client.Tests/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientTestBase.cs
  5. 17
      framework/test/Volo.Abp.AspNetCore.Mvc.Client.Tests/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientTestModule.cs
  6. 90
      framework/test/Volo.Abp.AspNetCore.Mvc.Client.Tests/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient_Tests.cs

1
framework/Volo.Abp.slnx

@ -181,6 +181,7 @@
<Project Path="test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo.Abp.AspNetCore.Mvc.UI.Tests.csproj" />
<Project Path="test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.csproj" />
<Project Path="test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo.Abp.AspNetCore.Mvc.Versioning.Tests.csproj" />
<Project Path="test/Volo.Abp.AspNetCore.Mvc.Client.Tests/Volo.Abp.AspNetCore.Mvc.Client.Tests.csproj" />
<Project Path="test/Volo.Abp.AspNetCore.Serilog.Tests/Volo.Abp.AspNetCore.Serilog.Tests.csproj" />
<Project Path="test/Volo.Abp.AspNetCore.SignalR.Tests/Volo.Abp.AspNetCore.SignalR.Tests.csproj" />
<Project Path="test/Volo.Abp.AspNetCore.Tests/Volo.Abp.AspNetCore.Tests.csproj" />

32
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs

@ -1,4 +1,5 @@
using System;
using System.Globalization;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
@ -84,20 +85,43 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu
private async Task<ApplicationConfigurationDto> GetRemoteConfigurationAsync()
{
var config = await ApplicationConfigurationAppService.GetAsync(
var cultureName = CultureInfo.CurrentUICulture.Name;
var configTask = ApplicationConfigurationAppService.GetAsync(
new ApplicationConfigurationRequestOptions
{
IncludeLocalizationResources = false
}
);
var localizationDto = await ApplicationLocalizationClientProxy.GetAsync(
new ApplicationLocalizationRequestDto {
CultureName = config.Localization.CurrentCulture.Name,
var localizationTask = ApplicationLocalizationClientProxy.GetAsync(
new ApplicationLocalizationRequestDto
{
CultureName = cultureName,
OnlyDynamics = true
}
);
var config = await configTask;
ApplicationLocalizationDto localizationDto;
// In most cases, the culture matches and we can reuse the concurrent request.
// If not, we discard it and make a new request with the correct culture.
if (string.Equals(config.Localization.CurrentCulture.Name, cultureName, StringComparison.OrdinalIgnoreCase))
{
localizationDto = await localizationTask;
}
else
{
localizationDto = await ApplicationLocalizationClientProxy.GetAsync(
new ApplicationLocalizationRequestDto
{
CultureName = config.Localization.CurrentCulture.Name,
OnlyDynamics = true
}
);
}
config.Localization.Resources = localizationDto.Resources;
return config;

17
framework/test/Volo.Abp.AspNetCore.Mvc.Client.Tests/Volo.Abp.AspNetCore.Mvc.Client.Tests.csproj

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.test.props" />
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.AspNetCore.Mvc.Client\Volo.Abp.AspNetCore.Mvc.Client.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
</ItemGroup>
</Project>

11
framework/test/Volo.Abp.AspNetCore.Mvc.Client.Tests/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientTestBase.cs

@ -0,0 +1,11 @@
using Volo.Abp.Testing;
namespace Volo.Abp.AspNetCore.Mvc.Client;
public abstract class AbpAspNetCoreMvcClientTestBase : AbpIntegratedTest<AbpAspNetCoreMvcClientTestModule>
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
}

17
framework/test/Volo.Abp.AspNetCore.Mvc.Client.Tests/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientTestModule.cs

@ -0,0 +1,17 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Autofac;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.Client;
[DependsOn(
typeof(AbpAspNetCoreMvcClientModule),
typeof(AbpAutofacModule)
)]
public class AbpAspNetCoreMvcClientTestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHttpContextAccessor();
}
}

90
framework/test/Volo.Abp.AspNetCore.Mvc.Client.Tests/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient_Tests.cs

@ -0,0 +1,90 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using NSubstitute;
using Shouldly;
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Client;
public class MvcCachedApplicationConfigurationClient_Tests : AbpAspNetCoreMvcClientTestBase
{
private AbpApplicationConfigurationClientProxy _configProxy;
private AbpApplicationLocalizationClientProxy _localizationProxy;
private readonly ICachedApplicationConfigurationClient _applicationConfigurationClient;
public MvcCachedApplicationConfigurationClient_Tests()
{
_applicationConfigurationClient = GetRequiredService<ICachedApplicationConfigurationClient>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
_configProxy = Substitute.For<AbpApplicationConfigurationClientProxy>();
_localizationProxy = Substitute.For<AbpApplicationLocalizationClientProxy>();
services.Replace(ServiceDescriptor.Transient(_ => _configProxy));
services.Replace(ServiceDescriptor.Transient(_ => _localizationProxy));
}
[Fact]
public async Task Should_Use_Concurrent_Requests_When_Culture_Matches()
{
var cultureName = "en";
_configProxy.GetAsync(Arg.Any<ApplicationConfigurationRequestOptions>()).Returns(CreateConfigDto(cultureName));
var expectedResources = new Dictionary<string, ApplicationLocalizationResourceDto>
{
["TestResource"] = new()
};
_localizationProxy.GetAsync(Arg.Any<ApplicationLocalizationRequestDto>()).Returns(new ApplicationLocalizationDto { Resources = expectedResources });
var result = await _applicationConfigurationClient.GetAsync();
result.Localization.Resources.ShouldBe(expectedResources);
await _configProxy.Received(1).GetAsync(Arg.Is<ApplicationConfigurationRequestOptions>(x => x.IncludeLocalizationResources == false));
await _localizationProxy.Received(1).GetAsync(Arg.Is<ApplicationLocalizationRequestDto>(x => x.CultureName == cultureName && x.OnlyDynamics == true));
}
[Fact]
public async Task Should_Refetch_Localization_When_Culture_Differs()
{
var currentCulture = "en";
var serverCulture = "tr";
_configProxy.GetAsync(Arg.Any<ApplicationConfigurationRequestOptions>()).Returns(CreateConfigDto(serverCulture));
var wrongResources = new Dictionary<string, ApplicationLocalizationResourceDto>();
var correctResources = new Dictionary<string, ApplicationLocalizationResourceDto>
{
["TestResource"] = new()
};
_localizationProxy.GetAsync(Arg.Is<ApplicationLocalizationRequestDto>(x => x.CultureName == currentCulture)).Returns(new ApplicationLocalizationDto { Resources = wrongResources });
_localizationProxy.GetAsync(Arg.Is<ApplicationLocalizationRequestDto>(x => x.CultureName == serverCulture)).Returns(new ApplicationLocalizationDto { Resources = correctResources });
var result = await _applicationConfigurationClient.GetAsync();
result.Localization.Resources.ShouldBe(correctResources);
await _localizationProxy.Received(1).GetAsync(Arg.Is<ApplicationLocalizationRequestDto>(x => x.CultureName == serverCulture));
}
private static ApplicationConfigurationDto CreateConfigDto(string cultureName)
{
return new ApplicationConfigurationDto
{
Localization =
{
CurrentCulture = new CurrentCultureDto { Name = cultureName }
}
};
}
}
Loading…
Cancel
Save