From a1577656b5bc2fa6c891b5c31a5328d039dec3d8 Mon Sep 17 00:00:00 2001 From: Halil ibrahim Kalkan Date: Wed, 11 Jul 2018 13:32:36 +0300 Subject: [PATCH] Localization improvements. --- .../Localization/AbpStringLocalizerFactory.cs | 51 +++++++++++++++---- .../Abp/Localization/LocalizationResource.cs | 21 +++----- .../LocalizationResourceExtensions.cs | 41 --------------- .../DependencyInjection_Tests.cs | 22 ++++++-- 4 files changed, 66 insertions(+), 69 deletions(-) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs index 1c2328c616..b7a633c5f9 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.Localization private readonly AbpLocalizationOptions _abpLocalizationOptions; private readonly IServiceProvider _serviceProvider; - private readonly ConcurrentDictionary _localizerCache; + private readonly ConcurrentDictionary _localizerCache; //TODO: It's better to use decorator pattern for IStringLocalizerFactory instead of getting ResourceManagerStringLocalizerFactory as a dependency. public AbpStringLocalizerFactory( @@ -27,27 +27,48 @@ namespace Volo.Abp.Localization _serviceProvider = serviceProvider; _abpLocalizationOptions = abpLocalizationOptions.Value; - _localizerCache = new ConcurrentDictionary(); + _localizerCache = new ConcurrentDictionary(); } public virtual IStringLocalizer Create(Type resourceType) { - var localizationResource = _abpLocalizationOptions.Resources.GetOrDefault(resourceType); - if (localizationResource == null) + var resource = _abpLocalizationOptions.Resources.GetOrDefault(resourceType); + if (resource == null) { return _innerFactory.Create(resourceType); } - return _localizerCache.GetOrAdd(resourceType, _ => CreateAbpStringLocalizer(localizationResource)); + return _localizerCache.GetOrAdd( + resourceType, + _ => CreateStringLocalizerCacheItem(resource) + ).Localizer; } - private AbpDictionaryBasedStringLocalizer CreateAbpStringLocalizer(LocalizationResource resource) + private StringLocalizerCacheItem CreateStringLocalizerCacheItem(LocalizationResource resource) { - resource.Initialize(_serviceProvider); //TODO: Use CreateScope? + using (var scope = _serviceProvider.CreateScope()) + { + resource.FillDictionaries(scope.ServiceProvider); + } + + if (!resource.RegisteredToUpdate) + { + resource.RegisteredToUpdate = true; + + foreach (var contributor in resource.Contributors) + { + contributor.Updated += (sender, args) => + { + _localizerCache.TryRemove(resource.ResourceType, out _); + }; + } + } - return new AbpDictionaryBasedStringLocalizer( - resource, - resource.BaseResourceTypes.Select(Create).ToList() + return new StringLocalizerCacheItem( + new AbpDictionaryBasedStringLocalizer( + resource, + resource.BaseResourceTypes.Select(Create).ToList() + ) ); } @@ -63,5 +84,15 @@ namespace Volo.Abp.Localization services.Replace(ServiceDescriptor.Singleton()); services.AddSingleton(); } + + private class StringLocalizerCacheItem + { + public AbpDictionaryBasedStringLocalizer Localizer { get; } + + public StringLocalizerCacheItem(AbpDictionaryBasedStringLocalizer localizer) + { + Localizer = localizer; + } + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs index 1dfc8e8b55..228608333c 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs @@ -25,6 +25,10 @@ namespace Volo.Abp.Localization [NotNull] public List BaseResourceTypes { get; } + public EventHandler Updated; + + internal bool RegisteredToUpdate { get; set; } + public LocalizationResource( [NotNull] Type resourceType, [CanBeNull] string defaultCultureName = null, @@ -46,25 +50,12 @@ namespace Volo.Abp.Localization AddBaseResourceTypes(); } - public virtual void Initialize(IServiceProvider serviceProvider) + public virtual void FillDictionaries(IServiceProvider serviceProvider) { - var context = new LocalizationResourceInitializationContext(this, serviceProvider); - Dictionaries.Clear(); - InitializeContributors(context); - foreach (var contributor in Contributors) - { - contributor.Updated += (sender, args) => - { - Dictionaries.Clear(); - InitializeContributors(context); - }; - } - } + var context = new LocalizationResourceInitializationContext(this, serviceProvider); - protected virtual void InitializeContributors(LocalizationResourceInitializationContext context) - { foreach (var contributor in Contributors) { foreach (var dictionary in contributor.GetDictionaries(context)) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceExtensions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceExtensions.cs index c2e4cd3178..3e2bd41435 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceExtensions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceExtensions.cs @@ -35,46 +35,5 @@ namespace Volo.Abp.Localization return localizationResource; } - - //public static LocalizationResource AddVirtualJson( - // [NotNull] this LocalizationResourceDictionary resourceDictionary, - // [CanBeNull] string defaultCultureName, - // [NotNull] string virtualPath) - //{ - // Check.NotNull(resourceDictionary, nameof(resourceDictionary)); - // Check.NotNull(virtualPath, nameof(virtualPath)); - - // return resourceDictionary - // .Add(defaultCultureName) - // .AddVirtualJson(virtualPath); - //} - - //public static LocalizationResource ExtendWithVirtualJson( - // [NotNull] this LocalizationResourceDictionary resourceDictionary, - // [NotNull] string virtualPath) - //{ - // Check.NotNull(resourceDictionary, nameof(resourceDictionary)); - - // return resourceDictionary - // .Get() - // .AddVirtualJson(virtualPath); - //} - - //public static LocalizationResource AddBaseTypes( - // [NotNull] this LocalizationResourceDictionary resourceDictionary, - // [NotNull] params Type[] types) - //{ - // Check.NotNull(resourceDictionary, nameof(resourceDictionary)); - // Check.NotNull(types, nameof(types)); - - // var localizationResource = resourceDictionary.Get(); - - // foreach (var type in types) - // { - // localizationResource.BaseResourceTypes.AddIfNotContains(type); - // } - - // return localizationResource; - //} } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs index a3a3dc08f0..64057659b6 100644 --- a/framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs @@ -15,10 +15,11 @@ namespace Microsoft.Extensions.DependencyInjection { MySingletonService singletonService; MyEmptyTransientService emptyTransientService; + MyTransientService1 transientService1; using (var scope = ServiceProvider.CreateScope()) { - var transientService1 = scope.ServiceProvider.GetRequiredService(); + transientService1 = scope.ServiceProvider.GetRequiredService(); emptyTransientService = scope.ServiceProvider.GetRequiredService(); transientService1.DoIt(); @@ -26,13 +27,20 @@ namespace Microsoft.Extensions.DependencyInjection singletonService = transientService1.SingletonService; singletonService.TransientInstances.Count.ShouldBe(2); + + transientService1.TransientInstances.Count.ShouldBe(2); + transientService1.TransientInstances.ForEach(ts => ts.IsDisposed.ShouldBeFalse()); } Assert.Equal(singletonService, GetRequiredService()); - singletonService.TransientInstances.Count.ShouldBe(2); + singletonService.ResolveTransient(); + + singletonService.TransientInstances.Count.ShouldBe(3); singletonService.TransientInstances.ForEach(ts => ts.IsDisposed.ShouldBeFalse()); + transientService1.TransientInstances.ForEach(ts => ts.IsDisposed.ShouldBeTrue()); + emptyTransientService.IsDisposed.ShouldBeTrue(); } @@ -77,15 +85,23 @@ namespace Microsoft.Extensions.DependencyInjection public class MyTransientService1 : ITransientDependency { public MySingletonService SingletonService { get; } + public IServiceProvider ServiceProvider { get; } + public List TransientInstances { get; } - public MyTransientService1(MySingletonService singletonService) + public MyTransientService1(MySingletonService singletonService, IServiceProvider serviceProvider) { SingletonService = singletonService; + ServiceProvider = serviceProvider; + TransientInstances = new List(); } public void DoIt() { SingletonService.ResolveTransient(); + + TransientInstances.Add( + ServiceProvider.GetRequiredService() + ); } }