fix #2747: Fix Mvc localization test once dnx support reading resources

This commit is contained in:
Kirthi Krishnamraju 2015-09-15 11:48:38 -07:00
parent 1833e06984
commit ed509f65a2
10 changed files with 185 additions and 232 deletions

View File

@ -1,9 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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 Microsoft.AspNet.Mvc.Localization.Internal;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Framework.Localization;
namespace Microsoft.Framework.DependencyInjection
{
@ -13,7 +14,7 @@ namespace Microsoft.Framework.DependencyInjection
public static class MvcLocalizationMvcBuilderExtensions
{
/// <summary>
/// Adds MVC localization to the application.
/// Adds MVC view localization to the application.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
@ -28,7 +29,7 @@ namespace Microsoft.Framework.DependencyInjection
}
/// <summary>
/// Adds MVC localization to the application.
/// Adds MVC view localization to the application.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="format">The view format for localized views.</param>
@ -42,7 +43,47 @@ namespace Microsoft.Framework.DependencyInjection
throw new ArgumentNullException(nameof(builder));
}
MvcLocalizationServices.AddLocalizationServices(builder.Services, format);
AddViewLocalization(builder, format, setupAction: null);
return builder;
}
/// <summary>
/// Adds MVC view localization to the application.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="setupAction">An action to configure the <see cref="LocalizationOptions"/>.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
public static IMvcBuilder AddViewLocalization(
this IMvcBuilder builder,
Action<LocalizationOptions> setupAction)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
AddViewLocalization(builder, LanguageViewLocationExpanderFormat.Suffix, setupAction);
return builder;
}
/// <summary>
/// Adds MVC view localization to the application.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="format">The view format for localized views.</param>
/// <param name="setupAction">An action to configure the <see cref="LocalizationOptions"/>.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
public static IMvcBuilder AddViewLocalization(
this IMvcBuilder builder,
LanguageViewLocationExpanderFormat format,
Action<LocalizationOptions> setupAction)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
MvcLocalizationServices.AddLocalizationServices(builder.Services, format, setupAction);
return builder;
}
}

View File

@ -1,9 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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 Microsoft.AspNet.Mvc.Localization.Internal;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Framework.Localization;
namespace Microsoft.Framework.DependencyInjection
{
@ -52,11 +53,62 @@ namespace Microsoft.Framework.DependencyInjection
throw new ArgumentNullException(nameof(builder));
}
builder.AddViews();
builder.AddRazorViewEngine();
MvcLocalizationServices.AddLocalizationServices(builder.Services, format, setupAction: null);
return builder;
}
/// <summary>
/// Adds MVC localization to the application.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="setupAction">An action to configure the <see cref="LocalizationOptions"/>.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
/// <remarks>
/// Adding localization also adds support for views via
/// <see cref="MvcViewFeaturesMvcCoreBuilderExtensions.AddViews(IMvcCoreBuilder)"/> and the Razor view engine
/// via <see cref="MvcRazorMvcCoreBuilderExtensions.AddRazorViewEngine(IMvcCoreBuilder)"/>.
/// </remarks>
public static IMvcCoreBuilder AddViewLocalization(
this IMvcCoreBuilder builder,
Action<LocalizationOptions> setupAction)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
return AddViewLocalization(builder, LanguageViewLocationExpanderFormat.Suffix, setupAction);
}
/// <summary>
/// Adds MVC localization to the application.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="format">The view format for localized views.</param>
/// <param name="setupAction">An action to configure the <see cref="LocalizationOptions"/>.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
/// <remarks>
/// Adding localization also adds support for views via
/// <see cref="MvcViewFeaturesMvcCoreBuilderExtensions.AddViews(IMvcCoreBuilder)"/> and the Razor view engine
/// via <see cref="MvcRazorMvcCoreBuilderExtensions.AddRazorViewEngine(IMvcCoreBuilder)"/>.
/// </remarks>
public static IMvcCoreBuilder AddViewLocalization(
this IMvcCoreBuilder builder,
LanguageViewLocationExpanderFormat format,
Action<LocalizationOptions> setupAction)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.AddViews();
builder.AddRazorViewEngine();
MvcLocalizationServices.AddLocalizationServices(builder.Services, format);
MvcLocalizationServices.AddLocalizationServices(builder.Services, format, setupAction);
return builder;
}
}

View File

@ -1,10 +1,12 @@
// 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.AspNet.Mvc.Razor;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.Localization;
using Microsoft.Framework.WebEncoders;
namespace Microsoft.AspNet.Mvc.Localization.Internal
@ -13,7 +15,8 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal
{
public static void AddLocalizationServices(
IServiceCollection services,
LanguageViewLocationExpanderFormat format)
LanguageViewLocationExpanderFormat format,
Action<LocalizationOptions> setupAction)
{
services.Configure<RazorViewEngineOptions>(
options =>
@ -29,7 +32,7 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal
services.TryAdd(ServiceDescriptor.Instance<IHtmlEncoder>(HtmlEncoder.Default));
}
services.AddLocalization();
services.AddLocalization(setupAction);
}
}
}

View File

@ -103,7 +103,6 @@ namespace Microsoft.AspNet.Mvc.Localization
{
baseName = baseName.Substring(1);
}
baseName = _applicationName + "." + baseName;
_localizer = _localizerFactory.Create(baseName, _applicationName);
}

View File

@ -2,12 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Resources;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.AspNet.Testing;
using Microsoft.Net.Http.Headers;
using Xunit;
@ -87,9 +84,6 @@ mypartial
{
get
{
// Dnx does not support reading resources yet. Coreclr return null value while trying to read resources.
// https://github.com/aspnet/Mvc/issues/2747
#if DNX451
var expected1 =
@"Hello there!!
Learn More
@ -97,20 +91,15 @@ Hi John ! You are in 2015 year and today is Thursday";
yield return new[] {"en-GB", expected1 };
var expected2 =
if (!TestPlatformHelper.IsMono)
{
// https://github.com/aspnet/Mvc/issues/3172
var expected2 =
@"Bonjour!
apprendre Encore Plus
Salut John ! Vous êtes en 2015 an aujourd'hui est Thursday";
yield return new[] { "fr", expected2 };
#else
var expectedCoreClr =
@"Hello there!!
Learn More
Hi";
yield return new[] {"en-GB", expectedCoreClr };
yield return new[] {"fr", expectedCoreClr };
#endif
yield return new[] { "fr", expected2 };
}
}
}
@ -125,14 +114,6 @@ Hi";
"Cookie",
new CookieHeaderValue("ASPNET_CULTURE", cultureCookie).ToString());
if (!value.StartsWith("en"))
{
// Manually generating .resources file since we don't autogenerate .resources file yet.
WriteResourceFile("HomeController." + value + ".resx");
WriteResourceFile("Views.Shared._LocalizationLayout.cshtml." + value + ".resx");
}
WriteResourceFile("Views.Home.Locpage.cshtml." + value + ".resx");
// Act
var response = await Client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
@ -140,44 +121,5 @@ Hi";
// Assert
Assert.Equal(expected, body.Trim());
}
private void WriteResourceFile(string resxFileName)
{
var resxFilePath = Path.Combine("..", "WebSites", SiteName, "Resources");
var resxFullFileName = Path.Combine(resxFilePath, resxFileName);
if (File.Exists(resxFullFileName))
{
using (var fs = File.OpenRead(resxFullFileName))
{
var document = XDocument.Load(fs);
var binDirPath = Path.Combine(resxFilePath, "bin");
if (!Directory.Exists(binDirPath))
{
Directory.CreateDirectory(binDirPath);
}
// Put in "bin" sub-folder of resx file
var targetPath = Path.Combine(
binDirPath,
Path.ChangeExtension(resxFileName, ".resources"));
using (var targetStream = File.Create(targetPath))
{
var rw = new ResourceWriter(targetStream);
foreach (var e in document.Root.Elements("data"))
{
var name = e.Attribute("name").Value;
var value = e.Element("value").Value;
rw.AddResource(name, value);
}
rw.Generate();
}
}
}
}
}
}

View File

@ -27,7 +27,8 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal
// Act
MvcLocalizationServices.AddLocalizationServices(
collection,
LanguageViewLocationExpanderFormat.Suffix);
LanguageViewLocationExpanderFormat.Suffix,
setupAction: null);
// Assert
Assert.Collection(collection,
@ -93,7 +94,8 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal
MvcLocalizationServices.AddLocalizationServices(
collection,
LanguageViewLocationExpanderFormat.Suffix);
LanguageViewLocationExpanderFormat.Suffix,
setupAction: null);
// Assert
Assert.Collection(collection,
@ -158,7 +160,8 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal
// Act
MvcLocalizationServices.AddLocalizationServices(
collection,
LanguageViewLocationExpanderFormat.Suffix);
LanguageViewLocationExpanderFormat.Suffix,
setupAction: null);
collection.Add(ServiceDescriptor.Transient(typeof(IHtmlLocalizer<>), typeof(TestHtmlLocalizer<>)));
collection.Add(ServiceDescriptor.Transient(typeof(IHtmlLocalizer), typeof(TestViewLocalizer)));
@ -235,6 +238,72 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal
Assert.Equal(ServiceLifetime.Singleton, service.Lifetime);
});
}
[Fact]
public void AddLocalizationServicesWithLocalizationOptions_AddsNeededServices()
{
// Arrange
var collection = new ServiceCollection();
// Act
MvcLocalizationServices.AddLocalizationServices(
collection,
LanguageViewLocationExpanderFormat.Suffix,
options => options.ResourcesPath = "Resources");
// Assert
Assert.Collection(collection,
service =>
{
Assert.Equal(typeof(IConfigureOptions<RazorViewEngineOptions>), service.ServiceType);
Assert.Equal(ServiceLifetime.Singleton, service.Lifetime);
},
service =>
{
Assert.Equal(typeof(IHtmlLocalizerFactory), service.ServiceType);
Assert.Equal(typeof(HtmlLocalizerFactory), service.ImplementationType);
Assert.Equal(ServiceLifetime.Singleton, service.Lifetime);
},
service =>
{
Assert.Equal(typeof(IHtmlLocalizer<>), service.ServiceType);
Assert.Equal(typeof(HtmlLocalizer<>), service.ImplementationType);
Assert.Equal(ServiceLifetime.Transient, service.Lifetime);
},
service =>
{
Assert.Equal(typeof(IViewLocalizer), service.ServiceType);
Assert.Equal(typeof(ViewLocalizer), service.ImplementationType);
Assert.Equal(ServiceLifetime.Transient, service.Lifetime);
},
service =>
{
Assert.Equal(typeof(IHtmlEncoder), service.ServiceType);
Assert.Equal(ServiceLifetime.Singleton, service.Lifetime);
},
service =>
{
Assert.Equal(typeof(IStringLocalizerFactory), service.ServiceType);
Assert.Equal(typeof(ResourceManagerStringLocalizerFactory), service.ImplementationType);
Assert.Equal(ServiceLifetime.Singleton, service.Lifetime);
},
service =>
{
Assert.Equal(typeof(IStringLocalizer<>), service.ServiceType);
Assert.Equal(typeof(StringLocalizer<>), service.ImplementationType);
Assert.Equal(ServiceLifetime.Transient, service.Lifetime);
},
service =>
{
Assert.Equal(typeof(IConfigureOptions<LocalizationOptions>), service.ServiceType);
Assert.Equal(ServiceLifetime.Singleton, service.Lifetime);
},
service =>
{
Assert.Equal(typeof(IOptions<>), service.ServiceType);
Assert.Equal(ServiceLifetime.Singleton, service.Lifetime);
});
}
}
public class TestViewLocalizer : IViewLocalizer

View File

@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Mvc.Localization.Test
htmlLocalizer.Setup(h => h["Hello"]).Returns(localizedString);
var htmlLocalizerFactory = new Mock<IHtmlLocalizerFactory>();
htmlLocalizerFactory.Setup(h => h.Create("TestApplication.example", "TestApplication"))
htmlLocalizerFactory.Setup(h => h.Create("example", "TestApplication"))
.Returns(htmlLocalizer.Object);
var viewLocalizer = new ViewLocalizer(htmlLocalizerFactory.Object, applicationEnvironment.Object);
@ -60,7 +60,7 @@ namespace Microsoft.AspNet.Mvc.Localization.Test
var htmlLocalizerFactory = new Mock<IHtmlLocalizerFactory>();
htmlLocalizerFactory.Setup(
h => h.Create("TestApplication.example", "TestApplication")).Returns(htmlLocalizer.Object);
h => h.Create("example", "TestApplication")).Returns(htmlLocalizer.Object);
var viewLocalizer = new ViewLocalizer(htmlLocalizerFactory.Object, applicationEnvironment.Object);

View File

@ -3,7 +3,6 @@
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Localization;
namespace LocalizationWebSite
{
@ -11,11 +10,7 @@ namespace LocalizationWebSite
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddViewLocalization();
// Adding TestStringLocalizerFactory since ResourceStringLocalizerFactory uses ResourceManager. DNX does
// not support getting non-enu resources from ResourceManager yet.
services.AddSingleton<IStringLocalizerFactory, TestStringLocalizerFactory>();
services.AddMvc().AddViewLocalization(options => options.ResourcesPath = "Resources");
}
public void Configure(IApplicationBuilder app)

View File

@ -1,96 +0,0 @@
// 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.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Resources;
using Microsoft.Framework.Localization;
using Microsoft.Framework.Localization.Internal;
namespace LocalizationWebSite
{
public class TestStringLocalizer : IStringLocalizer
{
private readonly IResourceNamesCache _resourceNamesCache;
private ResourceManager _resourceManager;
private readonly AssemblyWrapper _resourceAssemblyWrapper;
private readonly string _resourceBaseName;
private string _applicationBasePath;
public TestStringLocalizer(ResourceManager resourceManager,
AssemblyWrapper resourceAssembly,
string baseName,
IResourceNamesCache resourceNamesCache,
string applicationBasePath)
{
_resourceAssemblyWrapper = resourceAssembly;
_resourceManager = resourceManager;
_resourceBaseName = baseName;
_resourceNamesCache = resourceNamesCache;
_applicationBasePath = applicationBasePath;
}
public virtual LocalizedString this[string name]
{
get
{
var value = GetStringSafely(name, null);
return new LocalizedString(name, value ?? name, resourceNotFound: value == null);
}
}
public virtual LocalizedString this[string name, params object[] arguments]
{
get
{
var format = GetStringSafely(name, null);
var value = string.Format(format ?? name, arguments);
return new LocalizedString(name, value, resourceNotFound: format == null);
}
}
public IStringLocalizer WithCulture(CultureInfo culture)
{
return new TestStringLocalizer(_resourceManager,
_resourceAssemblyWrapper,
_resourceBaseName,
_resourceNamesCache,
_applicationBasePath);
}
public virtual IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures) =>
GetAllStrings(includeAncestorCultures, CultureInfo.CurrentUICulture);
protected IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures, CultureInfo culture)
{
throw new NotImplementedException();
}
protected string GetStringSafely(string name, CultureInfo culture)
{
var resourceValue = string.Empty;
#if DNX451
var cultureName = (culture ?? CultureInfo.CurrentUICulture).Name;
var resourceFile = _resourceManager.BaseName.Substring(_resourceManager.BaseName.IndexOf('.') + 1) + "." + cultureName;
var filePath = Path.Combine(_applicationBasePath, "Resources", "bin");
if (File.Exists(Path.Combine(filePath, resourceFile + ".resources")))
{
_resourceManager = ResourceManager.CreateFileBasedResourceManager(resourceFile, filePath, null);
}
#endif
try
{
// retrieve the value of the specified key
resourceValue = _resourceManager.GetString(name);
}
catch (MissingManifestResourceException)
{
return name;
}
return resourceValue;
}
}
}

View File

@ -1,52 +0,0 @@
// 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.Reflection;
using System.Resources;
using Microsoft.Framework.Localization;
using Microsoft.Framework.Localization.Internal;
using Microsoft.Dnx.Runtime;
namespace LocalizationWebSite
{
public class TestStringLocalizerFactory : IStringLocalizerFactory
{
private readonly IApplicationEnvironment _applicationEnvironment;
private readonly IResourceNamesCache _resourceNamesCache = new ResourceNamesCache();
public TestStringLocalizerFactory(IApplicationEnvironment applicationEnvironment)
{
_applicationEnvironment = applicationEnvironment;
}
public IStringLocalizer Create(Type resourceSource)
{
var typeInfo = resourceSource.GetTypeInfo();
var assembly = typeInfo.Assembly;
var baseName = typeInfo.FullName;
return new TestStringLocalizer(
new ResourceManager(resourceSource),
new AssemblyWrapper(assembly),
baseName,
_resourceNamesCache,
_applicationEnvironment.ApplicationBasePath);
}
public IStringLocalizer Create(string baseName, string location)
{
if (string.IsNullOrEmpty(location))
{
location = _applicationEnvironment.ApplicationName;
}
var assembly = Assembly.Load(new AssemblyName(location));
return new TestStringLocalizer(
new ResourceManager(baseName, assembly),
new AssemblyWrapper(assembly),
baseName,
_resourceNamesCache,
_applicationEnvironment.ApplicationBasePath);
}
}
}