Allow setting RootNamespace in ResourceLocationAttribute

This commit is contained in:
Ryan Brandenburg 2017-12-28 11:23:36 -08:00
Родитель 683ef56b76
Коммит bab2a50ec1
5 изменённых файлов: 142 добавлений и 12 удалений

Просмотреть файл

@ -68,7 +68,7 @@ namespace Microsoft.Extensions.Localization
throw new ArgumentNullException(nameof(typeInfo));
}
return GetResourcePrefix(typeInfo, new AssemblyName(typeInfo.Assembly.FullName).Name, _resourcesRelativePath);
return GetResourcePrefix(typeInfo, GetRootNamespace(typeInfo.Assembly), GetResourcePath(typeInfo.Assembly));
}
/// <summary>
@ -94,9 +94,17 @@ namespace Microsoft.Extensions.Localization
throw new ArgumentNullException(nameof(baseNamespace));
}
return string.IsNullOrEmpty(resourcesRelativePath)
? typeInfo.FullName
: baseNamespace + "." + resourcesRelativePath + TrimPrefix(typeInfo.FullName, baseNamespace + ".");
if (string.IsNullOrEmpty(resourcesRelativePath))
{
return typeInfo.FullName;
}
else
{
// This expectation is defined by dotnet's automatic resource storage.
// We have to conform to "{RootNamespace}.{ResourceLocation}.{FullTypeName - AssemblyName}".
var assemblyName = new AssemblyName(typeInfo.Assembly.FullName).Name;
return baseNamespace + "." + resourcesRelativePath + TrimPrefix(typeInfo.FullName, assemblyName + ".");
}
}
/// <summary>
@ -119,8 +127,9 @@ namespace Microsoft.Extensions.Localization
var assemblyName = new AssemblyName(baseNamespace);
var assembly = Assembly.Load(assemblyName);
var rootNamespace = GetRootNamespace(assembly);
var resourceLocation = GetResourcePath(assembly);
var locationPath = baseNamespace + "." + resourceLocation;
var locationPath = rootNamespace + "." + resourceLocation;
baseResourceName = locationPath + TrimPrefix(baseResourceName, baseNamespace + ".");
@ -141,11 +150,10 @@ namespace Microsoft.Extensions.Localization
}
var typeInfo = resourceSource.GetTypeInfo();
var assembly = typeInfo.Assembly;
var assemblyName = new AssemblyName(assembly.FullName);
var resourcePath = GetResourcePath(assembly);
var baseName = GetResourcePrefix(typeInfo, assemblyName.Name, resourcePath);
var baseName = GetResourcePrefix(typeInfo);
var assembly = typeInfo.Assembly;
return _localizerCache.GetOrAdd(baseName, _ => CreateResourceManagerStringLocalizer(assembly, baseName));
}
@ -217,6 +225,23 @@ namespace Microsoft.Extensions.Localization
return assembly.GetCustomAttribute<ResourceLocationAttribute>();
}
/// <summary>Gets a <see cref="RootNamespaceAttribute"/> from the provided <see cref="Assembly"/>.</summary>
/// <param name="assembly">The assembly to get a <see cref="RootNamespaceAttribute"/> from.</param>
/// <returns>The <see cref="RootNamespaceAttribute"/> associated with the given <see cref="Assembly"/>.</returns>
/// <remarks>This method is protected and virtual for testing purposes only.</remarks>
protected virtual RootNamespaceAttribute GetRootNamespaceAttribute(Assembly assembly)
{
return assembly.GetCustomAttribute<RootNamespaceAttribute>();
}
private string GetRootNamespace(Assembly assembly)
{
var rootNamespaceAttribute = GetRootNamespaceAttribute(assembly);
return rootNamespaceAttribute?.RootNamespace ??
new AssemblyName(assembly.FullName).Name;
}
private string GetResourcePath(Assembly assembly)
{
var resourceLocationAttribute = GetResourceLocationAttribute(assembly);

Просмотреть файл

@ -0,0 +1,35 @@
// 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;
namespace Microsoft.Extensions.Localization
{
/// <summary>
/// Provides the RootNamespace of an Assembly. The RootNamespace of the assembly is used by Localization to
/// determine the resource name to look for when RootNamespace differs from the AssemblyName.
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)]
public class RootNamespaceAttribute : Attribute
{
/// <summary>
/// Creates a new <see cref="RootNamespaceAttribute"/>.
/// </summary>
/// <param name="rootNamespace">The RootNamespace for this Assembly.</param>
public RootNamespaceAttribute(string rootNamespace)
{
if (string.IsNullOrEmpty(rootNamespace))
{
throw new ArgumentNullException(nameof(rootNamespace));
}
RootNamespace = rootNamespace;
}
/// <summary>
/// The RootNamespace of this Assembly. The RootNamespace of the assembly is used by Localization to
/// determine the resource name to look for when RootNamespace differs from the AssemblyName.
/// </summary>
public string RootNamespace { get; }
}
}

Просмотреть файл

@ -17,16 +17,20 @@ namespace Microsoft.Extensions.Localization.Tests
{
private ResourceLocationAttribute _resourceLocationAttribute;
private RootNamespaceAttribute _rootNamespaceAttribute;
public Assembly Assembly { get; private set; }
public string BaseName { get; private set; }
public TestResourceManagerStringLocalizerFactory(
IOptions<LocalizationOptions> localizationOptions,
ResourceLocationAttribute resourceLocationAttribute,
RootNamespaceAttribute rootNamespaceAttribute,
ILoggerFactory loggerFactory)
: base(localizationOptions, loggerFactory)
{
_resourceLocationAttribute = resourceLocationAttribute;
_rootNamespaceAttribute = rootNamespaceAttribute;
}
protected override ResourceLocationAttribute GetResourceLocationAttribute(Assembly assembly)
@ -34,6 +38,11 @@ namespace Microsoft.Extensions.Localization.Tests
return _resourceLocationAttribute;
}
protected override RootNamespaceAttribute GetRootNamespaceAttribute(Assembly assembly)
{
return _rootNamespaceAttribute;
}
protected override ResourceManagerStringLocalizer CreateResourceManagerStringLocalizer(Assembly assembly, string baseName)
{
BaseName = baseName;
@ -58,11 +67,13 @@ namespace Microsoft.Extensions.Localization.Tests
var typeFactory = new TestResourceManagerStringLocalizerFactory(
options.Object,
resourceLocationAttribute,
loggerFactory);
rootNamespaceAttribute: null,
loggerFactory: loggerFactory);
var stringFactory = new TestResourceManagerStringLocalizerFactory(
options.Object,
resourceLocationAttribute,
loggerFactory);
rootNamespaceAttribute: null,
loggerFactory: loggerFactory);
var type = typeof(ResourceManagerStringLocalizerFactoryTest);
var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
@ -111,6 +122,61 @@ namespace Microsoft.Extensions.Localization.Tests
Assert.NotSame(result1, result2);
}
[Fact]
public void Create_ResourceLocationAttribute_RootNamespaceIgnoredWhenNoLocation()
{
// Arrange
var locOptions = new LocalizationOptions();
var options = new Mock<IOptions<LocalizationOptions>>();
options.Setup(o => o.Value).Returns(locOptions);
var loggerFactory = NullLoggerFactory.Instance;
var resourcePath = Path.Combine("My", "Resources");
var rootNamespace = "MyNamespace";
var rootNamespaceAttribute = new RootNamespaceAttribute(rootNamespace);
var typeFactory = new TestResourceManagerStringLocalizerFactory(
options.Object,
resourceLocationAttribute: null,
rootNamespaceAttribute: rootNamespaceAttribute,
loggerFactory: loggerFactory);
var type = typeof(ResourceManagerStringLocalizerFactoryTest);
// Act
typeFactory.Create(type);
// Assert
Assert.Equal($"Microsoft.Extensions.Localization.Tests.ResourceManagerStringLocalizerFactoryTest", typeFactory.BaseName);
}
[Fact]
public void Create_ResourceLocationAttribute_UsesRootNamespace()
{
// Arrange
var locOptions = new LocalizationOptions();
var options = new Mock<IOptions<LocalizationOptions>>();
options.Setup(o => o.Value).Returns(locOptions);
var loggerFactory = NullLoggerFactory.Instance;
var resourcePath = Path.Combine("My", "Resources");
var rootNamespace = "MyNamespace";
var resourceLocationAttribute = new ResourceLocationAttribute(resourcePath);
var rootNamespaceAttribute = new RootNamespaceAttribute(rootNamespace);
var typeFactory = new TestResourceManagerStringLocalizerFactory(
options.Object,
resourceLocationAttribute,
rootNamespaceAttribute,
loggerFactory);
var type = typeof(ResourceManagerStringLocalizerFactoryTest);
// Act
typeFactory.Create(type);
// Assert
Assert.Equal($"MyNamespace.My.Resources.ResourceManagerStringLocalizerFactoryTest", typeFactory.BaseName);
}
[Fact]
public void Create_FromType_ResourcesPathDirectorySeperatorToDot()
{
@ -123,6 +189,7 @@ namespace Microsoft.Extensions.Localization.Tests
var factory = new TestResourceManagerStringLocalizerFactory(
options.Object,
resourceLocationAttribute: null,
rootNamespaceAttribute: null,
loggerFactory: loggerFactory);
// Act
@ -202,6 +269,7 @@ namespace Microsoft.Extensions.Localization.Tests
var factory = new TestResourceManagerStringLocalizerFactory(
options.Object,
resourceLocationAttribute: null,
rootNamespaceAttribute: null,
loggerFactory: loggerFactory);
// Act

Просмотреть файл

@ -4,4 +4,5 @@
using System.Reflection;
using Microsoft.Extensions.Localization;
[assembly: ResourceLocation("ResourceFolder")]
[assembly: ResourceLocation("ResourceFolder")]
[assembly: RootNamespace("Alternate.Namespace")]

Просмотреть файл

@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Alternate.Namespace</RootNamespace>
</PropertyGroup>
<ItemGroup>