diff --git a/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/ILocalizationAggregation.cs b/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/ILocalizationAggregation.cs index e2295f63..779736f1 100644 --- a/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/ILocalizationAggregation.cs +++ b/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/ILocalizationAggregation.cs @@ -6,6 +6,7 @@ namespace EShopOnAbp.WebGateway.Aggregations; public interface ILocalizationAggregation : ITransientDependency { + public string LocalizationRouteName { get; } public string LocalizationEndpoint { get; } public Task GetLocalizationAsync(LocalizationRequest input); } \ No newline at end of file diff --git a/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/Localization/CachedLocalizationService.cs b/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/Localization/CachedLocalizationService.cs index e665f3be..558a87a9 100644 --- a/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/Localization/CachedLocalizationService.cs +++ b/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/Localization/CachedLocalizationService.cs @@ -16,18 +16,12 @@ public class CachedLocalizationService : ISingletonDependency LocalizationDictionary = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); } - //TODO:skip url -> Use ServiceName_Culture as cache key public void AddOrUpdate(string serviceNameWithCulture, ApplicationLocalizationDto localizationInfo) { LocalizationDictionary.AddOrUpdate(serviceNameWithCulture, localizationInfo, (key, value) => localizationInfo); } - public ApplicationLocalizationDto Get(string serviceNameWithCulture) - { - return LocalizationDictionary.TryGetValue(serviceNameWithCulture, out var result) ? result : null; - } - - public IDictionary GetMultipleLocalizationsAsync(string[] serviceNamesWithCulture) + public IDictionary GetLocalizationsFromCacheAsync(string[] serviceNamesWithCulture) { return LocalizationDictionary .Where(kv => serviceNamesWithCulture.Contains(kv.Key)) diff --git a/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/Localization/RemoteLocalizationService.cs b/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/Localization/RemoteLocalizationService.cs index 869c601f..5d14f619 100644 --- a/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/Localization/RemoteLocalizationService.cs +++ b/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/Localization/RemoteLocalizationService.cs @@ -46,7 +46,7 @@ public class RemoteLocalizationService : IRemoteLocalizationService, ITransientD completedTasks.Add(completedTask.Key, completedTask.Value); completedResult.Add(completedTask.Key, result); - _logger.LogInformation($"Key: {completedTask.Key}, Value: {result}"); + _logger.LogInformation($"Localization Key: {completedTask.Key}, Value: {result}"); } catch (Exception ex) { @@ -70,23 +70,14 @@ public class RemoteLocalizationService : IRemoteLocalizationService, ITransientD private async Task MakeRequestAsync(HttpClient httpClient, string url) { - try - { - HttpResponseMessage response = await httpClient.GetAsync(url); - response.EnsureSuccessStatusCode(); + HttpResponseMessage response = await httpClient.GetAsync(url); + response.EnsureSuccessStatusCode(); - string content = await response.Content.ReadAsStringAsync(); - var options = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - }; - return JsonSerializer.Deserialize(content, options); - } - catch (Exception ex) + string content = await response.Content.ReadAsStringAsync(); + var options = new JsonSerializerOptions { - // Log or handle the exception, and return a default value or throw it again if needed - Console.WriteLine($"Error making request to {url}: {ex.Message}"); - throw; - } + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }; + return JsonSerializer.Deserialize(content, options); } } \ No newline at end of file diff --git a/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/LocalizationAggregation.cs b/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/LocalizationAggregation.cs index aeb813fa..09a5492b 100644 --- a/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/LocalizationAggregation.cs +++ b/gateways/web/src/EShopOnAbp.WebGateway/Aggregations/LocalizationAggregation.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Threading.Tasks; using EShopOnAbp.WebGateway.Aggregations.Localization; -using Microsoft.Extensions.Logging; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; namespace EShopOnAbp.WebGateway.Aggregations; @@ -10,48 +9,64 @@ namespace EShopOnAbp.WebGateway.Aggregations; public class LocalizationAggregation : ILocalizationAggregation { //Yarp localization route name - public string LocalizationEndpoint { get; } = "EshopOnAbpLocalization"; - private readonly ILogger _logger; + public string LocalizationRouteName { get; } = "EshopOnAbpLocalization"; + public string LocalizationEndpoint { get; } = "api/abp/application-localization"; + private readonly CachedLocalizationService _cachedLocalizationService; - private readonly RemoteLocalizationService _remoteLocalizationService; + private readonly IRemoteLocalizationService _remoteLocalizationService; - public LocalizationAggregation(ILogger logger, CachedLocalizationService cachedLocalizationService, RemoteLocalizationService remoteLocalizationService) + public LocalizationAggregation(CachedLocalizationService cachedLocalizationService, + IRemoteLocalizationService remoteLocalizationService) { - _logger = logger; _cachedLocalizationService = cachedLocalizationService; _remoteLocalizationService = remoteLocalizationService; } + public async Task GetLocalizationAsync(LocalizationRequest input) { // Check the cache service - var cachedLocalization = _cachedLocalizationService.GetMultipleLocalizationsAsync(input.LocalizationEndpoints.Keys.ToArray()); - + var cachedLocalization = _cachedLocalizationService + .GetLocalizationsFromCacheAsync(input.LocalizationEndpoints.Keys.ToArray()); + // Compare cache with input service list var missingLocalizationKeys = GetMissingLocalizations(cachedLocalization, input.LocalizationEndpoints); - + if (missingLocalizationKeys.Count != 0) { - // Make request to remote localization service - var remoteLocalizationResults = await _remoteLocalizationService - .GetMultipleLocalizationsAsync(input.LocalizationEndpoints - .Where(kv=> missingLocalizationKeys.Contains(kv.Key)) - .ToDictionary(k=>k.Key,v=>v.Value)); + // Make request to remote localization service to get missing localizations + var remoteLocalizationResults = + await GetLocalizationsFromRemoteAsync(missingLocalizationKeys, input.LocalizationEndpoints); + + // Update localization cache foreach (var result in remoteLocalizationResults) { _cachedLocalizationService.AddOrUpdate(result.Key, result.Value); } - cachedLocalization = _cachedLocalizationService.GetMultipleLocalizationsAsync(input.LocalizationEndpoints.Keys.ToArray()); + + cachedLocalization = _cachedLocalizationService + .GetLocalizationsFromCacheAsync(input.LocalizationEndpoints.Keys.ToArray()); } - + //merge result ApplicationLocalizationDto mergedResult = MergeLocalizations(cachedLocalization); - + //return result return mergedResult; } - private List GetMissingLocalizations(IDictionary serviceNameWithLocalization, Dictionary serviceNameWithUrls) + private async Task> GetLocalizationsFromRemoteAsync( + List missingLocalizationKeys, Dictionary localizationEndpoints) + { + return await _remoteLocalizationService + .GetMultipleLocalizationsAsync(localizationEndpoints + .Where(kv => missingLocalizationKeys.Contains(kv.Key)) + .ToDictionary(k => k.Key, v => v.Value)); + } + + private List GetMissingLocalizations( + IDictionary serviceNameWithLocalization, + Dictionary serviceNameWithUrls) { List missingKeysInCache = serviceNameWithUrls.Keys.Except(serviceNameWithLocalization.Keys).ToList(); List missingKeysInUrls = serviceNameWithLocalization.Keys.Except(serviceNameWithUrls.Keys).ToList(); @@ -59,10 +74,11 @@ public class LocalizationAggregation : ILocalizationAggregation return missingKeysInCache.Concat(missingKeysInUrls).ToList(); } - private ApplicationLocalizationDto MergeLocalizations(IDictionary localizationResults) + private ApplicationLocalizationDto MergeLocalizations( + IDictionary localizationResults) { var localizationDto = new ApplicationLocalizationDto(); - + foreach (var localization in localizationResults) { foreach (var resource in localization.Value.Resources) diff --git a/gateways/web/src/EShopOnAbp.WebGateway/ReverseProxyBuilderExtensions.cs b/gateways/web/src/EShopOnAbp.WebGateway/ReverseProxyBuilderExtensions.cs index b025dbe3..7064dad5 100644 --- a/gateways/web/src/EShopOnAbp.WebGateway/ReverseProxyBuilderExtensions.cs +++ b/gateways/web/src/EShopOnAbp.WebGateway/ReverseProxyBuilderExtensions.cs @@ -13,8 +13,6 @@ namespace EShopOnAbp.WebGateway; public static class ReverseProxyBuilderExtensions { - public static string LocalizationPath = "api/abp/application-localization"; - public static ReverseProxyConventionBuilder MapReverseProxyWithLocalization(this IEndpointRouteBuilder endpoints) { return endpoints.MapReverseProxy(proxyBuilder => @@ -24,11 +22,11 @@ public static class ReverseProxyBuilderExtensions var endpoint = context.GetEndpoint(); var localizationAggregation = context.RequestServices.GetRequiredService(); - if (localizationAggregation.LocalizationEndpoint == endpoint?.DisplayName) + if (localizationAggregation.LocalizationRouteName == endpoint?.DisplayName) { - LocalizationRequest input = CreateLocalizationRequestInput(context); + LocalizationRequest requestInput = CreateLocalizationRequestInput(context, localizationAggregation.LocalizationEndpoint); - var result = await localizationAggregation.GetLocalizationAsync(input); + var result = await localizationAggregation.GetLocalizationAsync(requestInput); await context.Response.WriteAsync(JsonSerializer.Serialize(result, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, @@ -44,14 +42,14 @@ public static class ReverseProxyBuilderExtensions }); } - private static LocalizationRequest CreateLocalizationRequestInput(HttpContext context) + private static LocalizationRequest CreateLocalizationRequestInput(HttpContext context, string localizationPath) { var proxyConfig = context.RequestServices.GetRequiredService(); context.Request.Query.TryGetValue("CultureName", out var cultureName); var input = new LocalizationRequest(cultureName); - string path = $"{LocalizationPath}?cultureName={cultureName}&onlyDynamics=false"; + string path = $"{localizationPath}?cultureName={cultureName}&onlyDynamics=false"; var clusterList = GetClusters(proxyConfig); foreach (var cluster in clusterList)