From 47287c508ee43c4f30b8000400fda1b01f68bfe2 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Sat, 9 Sep 2017 09:39:57 -0700 Subject: [PATCH] Added new extension methods to configure all MVC localization services [Fixes #5436] Must call `AddViewLocalization()` to use `IStringLocalizer` in an application --- .../MvcLocalizationMvcBuilderExtensions.cs | 239 +++++++++++++++- ...MvcLocalizationMvcCoreBuilderExtensions.cs | 255 +++++++++++++++++- .../Internal/MvcLocalizationServices.cs | 6 +- ...lizationServiceCollectionExtensionsTest.cs | 8 +- ...MvcLocalizationMvcBuilderExtensionsTest.cs | 146 ++++++++++ ...ocalizationMvcCoreBuilderExtensionsTest.cs | 146 ++++++++++ test/WebSites/RazorPagesWebSite/Startup.cs | 2 +- test/WebSites/RazorWebSite/Startup.cs | 2 +- 8 files changed, 777 insertions(+), 27 deletions(-) create mode 100644 test/Microsoft.AspNetCore.Mvc.Localization.Test/MvcLocalizationMvcBuilderExtensionsTest.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Localization.Test/MvcLocalizationMvcCoreBuilderExtensionsTest.cs diff --git a/src/Microsoft.AspNetCore.Mvc.Localization/DependencyInjection/MvcLocalizationMvcBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Localization/DependencyInjection/MvcLocalizationMvcBuilderExtensions.cs index 04088e5c92..ddeb4f25b4 100644 --- a/src/Microsoft.AspNetCore.Mvc.Localization/DependencyInjection/MvcLocalizationMvcBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Localization/DependencyInjection/MvcLocalizationMvcBuilderExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Mvc.DataAnnotations; using Microsoft.AspNetCore.Mvc.Localization.Internal; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.Extensions.Localization; @@ -9,12 +10,12 @@ using Microsoft.Extensions.Localization; namespace Microsoft.Extensions.DependencyInjection { /// - /// Extension methods for configuring MVC view localization. + /// Extension methods for configuring MVC view and data annotations localization services. /// public static class MvcLocalizationMvcBuilderExtensions { /// - /// Adds MVC view localization to the application. + /// Adds MVC view localization services to the application. /// /// The . /// The . @@ -29,7 +30,7 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds MVC view localization to the application. + /// Adds MVC view localization services to the application. /// /// The . /// The view format for localized views. @@ -48,7 +49,7 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds MVC view localization to the application. + /// Adds MVC view localization services to the application. /// /// The . /// An action to configure the . @@ -67,7 +68,7 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds MVC view localization to the application. + /// Adds MVC view localization services to the application. /// /// The . /// The view format for localized views. @@ -86,5 +87,233 @@ namespace Microsoft.Extensions.DependencyInjection MvcLocalizationServices.AddLocalizationServices(builder.Services, format, setupAction); return builder; } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcBuilder AddMvcLocalization(this IMvcBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction: null, + format: LanguageViewLocationExpanderFormat.Suffix, + dataAnnotationsLocalizationOptionsSetupAction: null); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// An action to configure the . + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcBuilder AddMvcLocalization( + this IMvcBuilder builder, + Action localizationOptionsSetupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction, + LanguageViewLocationExpanderFormat.Suffix, + dataAnnotationsLocalizationOptionsSetupAction: null); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// The view format for localized views. + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcBuilder AddMvcLocalization( + this IMvcBuilder builder, + LanguageViewLocationExpanderFormat format) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction: null, + format: format, + dataAnnotationsLocalizationOptionsSetupAction: null); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// An action to configure the + /// . + /// The view format for localized views. + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcBuilder AddMvcLocalization( + this IMvcBuilder builder, + Action localizationOptionsSetupAction, + LanguageViewLocationExpanderFormat format) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction: localizationOptionsSetupAction, + format: format, + dataAnnotationsLocalizationOptionsSetupAction: null); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// An action to configure the + /// . + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcBuilder AddMvcLocalization( + this IMvcBuilder builder, + Action dataAnnotationsLocalizationOptionsSetupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction: null, + format: LanguageViewLocationExpanderFormat.Suffix, + dataAnnotationsLocalizationOptionsSetupAction: dataAnnotationsLocalizationOptionsSetupAction); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// An action to configure the + /// . + /// An action to configure the + /// . + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcBuilder AddMvcLocalization( + this IMvcBuilder builder, + Action localizationOptionsSetupAction, + Action dataAnnotationsLocalizationOptionsSetupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction: localizationOptionsSetupAction, + format: LanguageViewLocationExpanderFormat.Suffix, + dataAnnotationsLocalizationOptionsSetupAction: dataAnnotationsLocalizationOptionsSetupAction); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// The view format for localized views. + /// An action to configure the + /// . + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcBuilder AddMvcLocalization( + this IMvcBuilder builder, + LanguageViewLocationExpanderFormat format, + Action dataAnnotationsLocalizationOptionsSetupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction: null, + format: format, + dataAnnotationsLocalizationOptionsSetupAction: dataAnnotationsLocalizationOptionsSetupAction); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// An action to configure the . + /// Can be null. + /// The view format for localized views. + /// An action to configure + /// the . Can be null. + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcBuilder AddMvcLocalization( + this IMvcBuilder builder, + Action localizationOptionsSetupAction, + LanguageViewLocationExpanderFormat format, + Action dataAnnotationsLocalizationOptionsSetupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder + .AddViewLocalization(format, localizationOptionsSetupAction) + .AddDataAnnotationsLocalization(dataAnnotationsLocalizationOptionsSetupAction); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Localization/DependencyInjection/MvcLocalizationMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Localization/DependencyInjection/MvcLocalizationMvcCoreBuilderExtensions.cs index fc1474bb16..27b1f90a7f 100644 --- a/src/Microsoft.AspNetCore.Mvc.Localization/DependencyInjection/MvcLocalizationMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Localization/DependencyInjection/MvcLocalizationMvcCoreBuilderExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Mvc.DataAnnotations; using Microsoft.AspNetCore.Mvc.Localization.Internal; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.Extensions.Localization; @@ -9,15 +10,15 @@ using Microsoft.Extensions.Localization; namespace Microsoft.Extensions.DependencyInjection { /// - /// Extension methods for configuring MVC view localization. + /// Extension methods for configuring MVC view and data annotations localization services. /// public static class MvcLocalizationMvcCoreBuilderExtensions { /// - /// Adds MVC localization to the application. + /// Adds MVC view localization services to the application. /// - /// The . - /// The . + /// The . + /// The . /// /// Adding localization also adds support for views via /// and the Razor view engine @@ -34,11 +35,11 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds MVC localization to the application. + /// Adds MVC view localization services to the application. /// - /// The . + /// The . /// The view format for localized views. - /// The . + /// The . /// /// Adding localization also adds support for views via /// and the Razor view engine @@ -61,11 +62,11 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds MVC localization to the application. + /// Adds MVC view localization services to the application. /// - /// The . + /// The . /// An action to configure the . - /// The . + /// The . /// /// Adding localization also adds support for views via /// and the Razor view engine @@ -84,12 +85,12 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds MVC localization to the application. + /// Adds MVC view localization services to the application. /// - /// The . + /// The . /// The view format for localized views. /// An action to configure the . - /// The . + /// The . /// /// Adding localization also adds support for views via /// and the Razor view engine @@ -111,5 +112,233 @@ namespace Microsoft.Extensions.DependencyInjection MvcLocalizationServices.AddLocalizationServices(builder.Services, format, setupAction); return builder; } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcCoreBuilder AddMvcLocalization(this IMvcCoreBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction: null, + format: LanguageViewLocationExpanderFormat.Suffix, + dataAnnotationsLocalizationOptionsSetupAction: null); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// An action to configure the . + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcCoreBuilder AddMvcLocalization( + this IMvcCoreBuilder builder, + Action localizationOptionsSetupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction, + LanguageViewLocationExpanderFormat.Suffix, + dataAnnotationsLocalizationOptionsSetupAction: null); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// The view format for localized views. + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcCoreBuilder AddMvcLocalization( + this IMvcCoreBuilder builder, + LanguageViewLocationExpanderFormat format) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction: null, + format: format, + dataAnnotationsLocalizationOptionsSetupAction: null); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// An action to configure the + /// . + /// The view format for localized views. + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcCoreBuilder AddMvcLocalization( + this IMvcCoreBuilder builder, + Action localizationOptionsSetupAction, + LanguageViewLocationExpanderFormat format) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction: localizationOptionsSetupAction, + format: format, + dataAnnotationsLocalizationOptionsSetupAction: null); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// An action to configure + /// the . + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcCoreBuilder AddMvcLocalization( + this IMvcCoreBuilder builder, + Action dataAnnotationsLocalizationOptionsSetupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction: null, + format: LanguageViewLocationExpanderFormat.Suffix, + dataAnnotationsLocalizationOptionsSetupAction: dataAnnotationsLocalizationOptionsSetupAction); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// An action to configure the + /// . + /// An action to configure the + /// . + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcCoreBuilder AddMvcLocalization( + this IMvcCoreBuilder builder, + Action localizationOptionsSetupAction, + Action dataAnnotationsLocalizationOptionsSetupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction: localizationOptionsSetupAction, + format: LanguageViewLocationExpanderFormat.Suffix, + dataAnnotationsLocalizationOptionsSetupAction: dataAnnotationsLocalizationOptionsSetupAction); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// The view format for localized views. + /// An action to configure the + /// . + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcCoreBuilder AddMvcLocalization( + this IMvcCoreBuilder builder, + LanguageViewLocationExpanderFormat format, + Action dataAnnotationsLocalizationOptionsSetupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddMvcLocalization( + builder, + localizationOptionsSetupAction: null, + format: format, + dataAnnotationsLocalizationOptionsSetupAction: dataAnnotationsLocalizationOptionsSetupAction); + } + + /// + /// Adds MVC view and data annotations localization services to the application. + /// + /// The . + /// An action to configure + /// the . Can be null. + /// The view format for localized views. + /// An action to configure + /// the . Can be null. + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcCoreBuilder AddMvcLocalization( + this IMvcCoreBuilder builder, + Action localizationOptionsSetupAction, + LanguageViewLocationExpanderFormat format, + Action dataAnnotationsLocalizationOptionsSetupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder + .AddViewLocalization(format, localizationOptionsSetupAction) + .AddDataAnnotationsLocalization(dataAnnotationsLocalizationOptionsSetupAction); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Localization/Internal/MvcLocalizationServices.cs b/src/Microsoft.AspNetCore.Mvc.Localization/Internal/MvcLocalizationServices.cs index 13951ed3ab..4e1f26ebc0 100644 --- a/src/Microsoft.AspNetCore.Mvc.Localization/Internal/MvcLocalizationServices.cs +++ b/src/Microsoft.AspNetCore.Mvc.Localization/Internal/MvcLocalizationServices.cs @@ -16,8 +16,8 @@ namespace Microsoft.AspNetCore.Mvc.Localization.Internal LanguageViewLocationExpanderFormat format, Action setupAction) { - AddMvcLocalizationServices(services, format, setupAction); - + AddMvcViewLocalizationServices(services, format, setupAction); + if (setupAction == null) { services.AddLocalization(); @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Mvc.Localization.Internal } // To enable unit testing only 'MVC' specific services - public static void AddMvcLocalizationServices( + public static void AddMvcViewLocalizationServices( IServiceCollection services, LanguageViewLocationExpanderFormat format, Action setupAction) diff --git a/test/Microsoft.AspNetCore.Mvc.Localization.Test/Internal/MvcLocalizationServiceCollectionExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Localization.Test/Internal/MvcLocalizationServiceCollectionExtensionsTest.cs index 752e68105a..02f654fb3b 100644 --- a/test/Microsoft.AspNetCore.Mvc.Localization.Test/Internal/MvcLocalizationServiceCollectionExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Localization.Test/Internal/MvcLocalizationServiceCollectionExtensionsTest.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Mvc.Localization.Internal var collection = new ServiceCollection(); // Act - MvcLocalizationServices.AddMvcLocalizationServices( + MvcLocalizationServices.AddMvcViewLocalizationServices( collection, LanguageViewLocationExpanderFormat.Suffix, setupAction: null); @@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Mvc.Localization.Internal collection.Add(ServiceDescriptor.Transient(typeof(IViewLocalizer), typeof(TestViewLocalizer))); collection.Add(ServiceDescriptor.Singleton(typeof(HtmlEncoder), testEncoder)); - MvcLocalizationServices.AddMvcLocalizationServices( + MvcLocalizationServices.AddMvcViewLocalizationServices( collection, LanguageViewLocationExpanderFormat.Suffix, setupAction: null); @@ -119,7 +119,7 @@ namespace Microsoft.AspNetCore.Mvc.Localization.Internal }); // Act - MvcLocalizationServices.AddMvcLocalizationServices( + MvcLocalizationServices.AddMvcViewLocalizationServices( collection, LanguageViewLocationExpanderFormat.Suffix, setupAction: null); @@ -186,7 +186,7 @@ namespace Microsoft.AspNetCore.Mvc.Localization.Internal var collection = new ServiceCollection(); // Act - MvcLocalizationServices.AddMvcLocalizationServices( + MvcLocalizationServices.AddMvcViewLocalizationServices( collection, LanguageViewLocationExpanderFormat.Suffix, options => options.ResourcesPath = "Resources"); diff --git a/test/Microsoft.AspNetCore.Mvc.Localization.Test/MvcLocalizationMvcBuilderExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Localization.Test/MvcLocalizationMvcBuilderExtensionsTest.cs new file mode 100644 index 0000000000..1b0b4e947f --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Localization.Test/MvcLocalizationMvcBuilderExtensionsTest.cs @@ -0,0 +1,146 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Linq; +using Microsoft.AspNetCore.Mvc.ApplicationParts; +using Microsoft.AspNetCore.Mvc.DataAnnotations; +using Microsoft.AspNetCore.Mvc.Razor; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.Localization.Test +{ + public class MvcLocalizationMvcBuilderExtensionsTest + { + public static TheoryData MvcBuilderExtensionsData() + { + var builder1 = new TestMvcBuilder(); + builder1.AddMvcLocalization(); + + var builder2 = new TestMvcBuilder(); + builder2.AddMvcLocalization(LanguageViewLocationExpanderFormat.SubFolder); + + var builder3 = new TestMvcBuilder(); + builder3.AddMvcLocalization(localizationOptionsSetupAction: l => l.ResourcesPath = "Resources"); + + var builder4 = new TestMvcBuilder(); + builder4.AddMvcLocalization( + localizationOptionsSetupAction: l => l.ResourcesPath = "Resources", + format: LanguageViewLocationExpanderFormat.SubFolder); + + return new TheoryData() + { + builder1, builder2, builder3, builder4 + }; + } + + [Theory] + [MemberData(nameof(MvcBuilderExtensionsData))] + public void AddsRequiredServices(IMvcBuilder mvcBuilder) + { + // Assert + var services = mvcBuilder.Services; + // Base localization services + var service = services.FirstOrDefault( + sd => sd.ServiceType == typeof(IStringLocalizerFactory)); + Assert.NotNull(service); + Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); + Assert.Equal(typeof(ResourceManagerStringLocalizerFactory), service.ImplementationType); + + service = services.FirstOrDefault( + sd => sd.ServiceType == typeof(IStringLocalizer<>)); + Assert.NotNull(service); + Assert.Equal(ServiceLifetime.Transient, service.Lifetime); + Assert.Equal(typeof(StringLocalizer<>), service.ImplementationType); + + // View localization services + service = services.FirstOrDefault( + sd => sd.ServiceType == typeof(IConfigureOptions)); + Assert.NotNull(service); + Assert.Equal(ServiceLifetime.Transient, service.Lifetime); + + service = services.FirstOrDefault( + sd => sd.ServiceType == typeof(IConfigureOptions)); + Assert.NotNull(service); + Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); + + service = services.FirstOrDefault(sd => sd.ServiceType == typeof(IHtmlLocalizerFactory)); + Assert.NotNull(service); + Assert.Equal(typeof(HtmlLocalizerFactory), service.ImplementationType); + Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); + + service = services.FirstOrDefault(sd => sd.ServiceType == typeof(IHtmlLocalizer<>)); + Assert.NotNull(service); + Assert.Equal(typeof(HtmlLocalizer<>), service.ImplementationType); + Assert.Equal(ServiceLifetime.Transient, service.Lifetime); + + service = services.FirstOrDefault(sd => sd.ServiceType == typeof(IViewLocalizer)); + Assert.NotNull(service); + Assert.Equal(typeof(ViewLocalizer), service.ImplementationType); + Assert.Equal(ServiceLifetime.Transient, service.Lifetime); + } + + [Fact] + public void SetsLocalizationOptions_AsExpected() + { + // Arrange + var builder = new TestMvcBuilder(); + + // Act + builder.AddMvcLocalization( + localizationOptionsSetupAction: options => options.ResourcesPath = "TestResources"); + + // Assert + var serviceProvider = builder.Services.BuildServiceProvider(); + var actualOptions = serviceProvider.GetRequiredService>(); + Assert.Equal("TestResources", actualOptions.Value.ResourcesPath); + } + + [Fact] + public void SetsDataAnnotationsOptions_AsExpected() + { + // Arrange + var builder = new TestMvcBuilder(); + var dataAnnotationLocalizerProvider = new Func((type, factory) => + { + return null; + }); + + // Act + builder.AddMvcLocalization( + dataAnnotationsLocalizationOptionsSetupAction: options + => options.DataAnnotationLocalizerProvider = dataAnnotationLocalizerProvider); + + // Assert + var serviceProvider = builder.Services.BuildServiceProvider(); + var actualOptions = serviceProvider.GetRequiredService>(); + Assert.Same(dataAnnotationLocalizerProvider, actualOptions.Value.DataAnnotationLocalizerProvider); + } + + private ServiceDescriptor GetService(IServiceCollection services, Type serviceType) + { + return services.FirstOrDefault(sd => sd.ServiceType == serviceType); + } + + private class TestMvcBuilder : IMvcBuilder + { + IServiceCollection _services; + public IServiceCollection Services + { + get + { + if (_services == null) + { + _services = new ServiceCollection(); + } + return _services; + } + } + + public ApplicationPartManager PartManager => new ApplicationPartManager(); + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Localization.Test/MvcLocalizationMvcCoreBuilderExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Localization.Test/MvcLocalizationMvcCoreBuilderExtensionsTest.cs new file mode 100644 index 0000000000..1412d35c94 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Localization.Test/MvcLocalizationMvcCoreBuilderExtensionsTest.cs @@ -0,0 +1,146 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Linq; +using Microsoft.AspNetCore.Mvc.ApplicationParts; +using Microsoft.AspNetCore.Mvc.DataAnnotations; +using Microsoft.AspNetCore.Mvc.Razor; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.Localization.Test +{ + public class MvcLocalizationMvcCoreBuilderExtensionsTest + { + public static TheoryData MvcCoreBuilderExtensionsData() + { + var builder1 = new TestMvcCoreBuilder(); + builder1.AddMvcLocalization(); + + var builder2 = new TestMvcCoreBuilder(); + builder2.AddMvcLocalization(LanguageViewLocationExpanderFormat.SubFolder); + + var builder3 = new TestMvcCoreBuilder(); + builder3.AddMvcLocalization(localizationOptionsSetupAction: l => l.ResourcesPath = "Resources"); + + var builder4 = new TestMvcCoreBuilder(); + builder4.AddMvcLocalization( + localizationOptionsSetupAction: l => l.ResourcesPath = "Resources", + format: LanguageViewLocationExpanderFormat.SubFolder); + + return new TheoryData() + { + builder1, builder2, builder3, builder4 + }; + } + + [Theory] + [MemberData(nameof(MvcCoreBuilderExtensionsData))] + public void AddsRequiredServices(IMvcCoreBuilder mvcCoreBuilder) + { + // Assert + var services = mvcCoreBuilder.Services; + // Base localization services + var service = services.FirstOrDefault( + sd => sd.ServiceType == typeof(IStringLocalizerFactory)); + Assert.NotNull(service); + Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); + Assert.Equal(typeof(ResourceManagerStringLocalizerFactory), service.ImplementationType); + + service = services.FirstOrDefault( + sd => sd.ServiceType == typeof(IStringLocalizer<>)); + Assert.NotNull(service); + Assert.Equal(ServiceLifetime.Transient, service.Lifetime); + Assert.Equal(typeof(StringLocalizer<>), service.ImplementationType); + + // View localization services + service = services.FirstOrDefault( + sd => sd.ServiceType == typeof(IConfigureOptions)); + Assert.NotNull(service); + Assert.Equal(ServiceLifetime.Transient, service.Lifetime); + + service = services.FirstOrDefault( + sd => sd.ServiceType == typeof(IConfigureOptions)); + Assert.NotNull(service); + Assert.Equal(ServiceLifetime.Transient, service.Lifetime); + + service = services.FirstOrDefault(sd => sd.ServiceType == typeof(IHtmlLocalizerFactory)); + Assert.NotNull(service); + Assert.Equal(typeof(HtmlLocalizerFactory), service.ImplementationType); + Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); + + service = services.FirstOrDefault(sd => sd.ServiceType == typeof(IHtmlLocalizer<>)); + Assert.NotNull(service); + Assert.Equal(typeof(HtmlLocalizer<>), service.ImplementationType); + Assert.Equal(ServiceLifetime.Transient, service.Lifetime); + + service = services.FirstOrDefault(sd => sd.ServiceType == typeof(IViewLocalizer)); + Assert.NotNull(service); + Assert.Equal(typeof(ViewLocalizer), service.ImplementationType); + Assert.Equal(ServiceLifetime.Transient, service.Lifetime); + } + + [Fact] + public void SetsLocalizationOptions_AsExpected() + { + // Arrange + var builder = new TestMvcCoreBuilder(); + + // Act + builder.AddMvcLocalization( + localizationOptionsSetupAction: options => options.ResourcesPath = "TestResources"); + + // Assert + var serviceProvider = builder.Services.BuildServiceProvider(); + var actualOptions = serviceProvider.GetRequiredService>(); + Assert.Equal("TestResources", actualOptions.Value.ResourcesPath); + } + + [Fact] + public void SetsDataAnnotationsOptions_AsExpected() + { + // Arrange + var builder = new TestMvcCoreBuilder(); + var dataAnnotationLocalizerProvider = new Func((type, factory) => + { + return null; + }); + + // Act + builder.AddMvcLocalization( + dataAnnotationsLocalizationOptionsSetupAction: options + => options.DataAnnotationLocalizerProvider = dataAnnotationLocalizerProvider); + + // Assert + var serviceProvider = builder.Services.BuildServiceProvider(); + var actualOptions = serviceProvider.GetRequiredService>(); + Assert.Same(dataAnnotationLocalizerProvider, actualOptions.Value.DataAnnotationLocalizerProvider); + } + + private ServiceDescriptor GetService(IServiceCollection services, Type serviceType) + { + return services.FirstOrDefault(sd => sd.ServiceType == serviceType); + } + + private class TestMvcCoreBuilder : IMvcCoreBuilder + { + IServiceCollection _services; + public IServiceCollection Services + { + get + { + if (_services == null) + { + _services = new ServiceCollection(); + } + return _services; + } + } + + public ApplicationPartManager PartManager => new ApplicationPartManager(); + } + } +} diff --git a/test/WebSites/RazorPagesWebSite/Startup.cs b/test/WebSites/RazorPagesWebSite/Startup.cs index 9ea2793f1c..718789325d 100644 --- a/test/WebSites/RazorPagesWebSite/Startup.cs +++ b/test/WebSites/RazorPagesWebSite/Startup.cs @@ -14,7 +14,7 @@ namespace RazorPagesWebSite { services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => options.LoginPath = "/Login"); services.AddMvc() - .AddViewLocalization() + .AddMvcLocalization() .AddRazorPagesOptions(options => { options.Conventions.AuthorizePage("/HelloWorldWithAuth"); diff --git a/test/WebSites/RazorWebSite/Startup.cs b/test/WebSites/RazorWebSite/Startup.cs index 7fb43f75e8..ebe16f7102 100644 --- a/test/WebSites/RazorWebSite/Startup.cs +++ b/test/WebSites/RazorWebSite/Startup.cs @@ -43,7 +43,7 @@ namespace RazorWebSite options.HtmlHelperOptions.ValidationMessageElement = "validationMessageElement"; options.HtmlHelperOptions.ValidationSummaryMessageElement = "validationSummaryElement"; }) - .AddViewLocalization(LanguageViewLocationExpanderFormat.SubFolder); + .AddMvcLocalization(LanguageViewLocationExpanderFormat.SubFolder); services.AddTransient(); services.AddTransient();