单独项目中的本地化 Asp.net 核心 MVC
Localization in separate project Asp.net Core MVC
我刚升级到 Rc2,以前可以用的东西不再用了。我在一个单独的项目中有几个 resx 文件,我使用自定义 class 来访问数据。现在我在 运行 时收到以下错误:
MissingManifestResourceException:找不到任何适合指定文化或中性文化的资源。确保 "GarageWeb.Core.CoreResources.resources" 在编译时已正确嵌入或链接到程序集 "GarageWeb.Core" 中,或者确保所需的所有附属程序集都是可加载且已完全签名的。
编辑:我对此进行了简化并创建了一个控制台应用程序,该应用程序删除了除此处重现错误所需的所有内容外的所有内容:https://github.com/GarageWeb/ResourceTest
这里是访问资源的class:
public class ResourceService : IResourceService
{
private readonly ILoggingService _loggingService;
private readonly ICoreGlobalResourceService _coreGlobalResources;
private readonly ISiteGlobalResourceService _siteGlobalResources;
public ResourceService(ILoggingService loggingService, ICoreGlobalResourceService coreGlobalResourceService, ISiteGlobalResourceService siteGlobalResources)
{
_loggingService = loggingService;
_coreGlobalResources = coreGlobalResourceService;
_siteGlobalResources = siteGlobalResources;
}
public string GetGlobalText(string resourceKey, bool includeBrackets = true)
{
var localizedString = _coreGlobalResources.ResourceManager.GetString(resourceKey);
if (string.IsNullOrEmpty(localizedString))
{
localizedString = _siteGlobalResources.ResourceManager.GetString(resourceKey);
}
if (string.IsNullOrEmpty(localizedString) && includeBrackets)
{
_loggingService.LogInvalidResource(resourceKey);
}
if (includeBrackets)
{
return localizedString ?? "[" + resourceKey + "]";
}
return localizedString ?? resourceKey;
}
public string BuildMessageFromResource(string resourceKey, string placeHolderResourceKey1,
bool includeBrackets = true)
{
var errorString = string.Format(CultureInfo.CurrentCulture, GetGlobalText(resourceKey, includeBrackets),
GetGlobalText(placeHolderResourceKey1, includeBrackets));
return errorString;
}
public string BuildMessageFromResourceAndArray(string resourceKey, string[] arrayOfValues,
bool includeBrackets = true)
{
var placeHolderValue = "";
for (var i = 0; i < arrayOfValues.Length; i++)
{
if (i + 1 == arrayOfValues.Length)
{
placeHolderValue += GetGlobalText(arrayOfValues[i], includeBrackets);
}
else
{
placeHolderValue += GetGlobalText(arrayOfValues[i], includeBrackets) + ", ";
}
}
var errorString = string.Format(CultureInfo.CurrentCulture, GetGlobalText(resourceKey, includeBrackets),
placeHolderValue);
return errorString;
}
public string BuildMessageFromResourceAndTwoArrays(string resourceKey, string[] firstArrayOfValues,
string[] secondArrayOfValues,
bool includeBrackets = true)
{
var placeHolderOneValue = "";
var placeHolderTwoValue = "";
for (var i = 0; i < firstArrayOfValues.Length; i++)
{
if (i + 1 == firstArrayOfValues.Length)
{
placeHolderOneValue += GetGlobalText(firstArrayOfValues[i], includeBrackets);
}
else
{
placeHolderOneValue += GetGlobalText(firstArrayOfValues[i], includeBrackets) + ", ";
}
}
for (var i = 0; i < secondArrayOfValues.Length; i++)
{
if (i + 1 == secondArrayOfValues.Length)
{
placeHolderTwoValue += GetGlobalText(secondArrayOfValues[i], includeBrackets);
}
else
{
placeHolderTwoValue += GetGlobalText(secondArrayOfValues[i], includeBrackets) + ", ";
}
}
var errorString = string.Format(CultureInfo.CurrentCulture, GetGlobalText(resourceKey, includeBrackets),
placeHolderOneValue, placeHolderTwoValue);
return errorString;
}
public string BuildMessageFromResource(string resourceKey, string placeHolderResourceKey1,
string placeHolderResourceKey2, bool includeBrackets = true)
{
var errorString = string.Format(CultureInfo.CurrentCulture, GetGlobalText(resourceKey, includeBrackets),
GetGlobalText(placeHolderResourceKey1, includeBrackets),
GetGlobalText(placeHolderResourceKey2, includeBrackets));
return errorString;
}
public string BuildMessageFromResource(string resourceKey, string placeHolderResourceKey1,
string placeHolderResourceKey2, string placeHolderResourceKey3,
bool includeBrackets = true)
{
var errorString = string.Format(CultureInfo.CurrentCulture, GetGlobalText(resourceKey, includeBrackets),
GetGlobalText(placeHolderResourceKey1, includeBrackets),
GetGlobalText(placeHolderResourceKey2, includeBrackets),
GetGlobalText(placeHolderResourceKey3, includeBrackets));
return errorString;
}
}
这里失败了:var localizedString = _coreGlobalResources.ResourceManager.GetString(resourceKey);
有什么想法吗?有没有一种新的方法来嵌入这些资源?
因此,如果我将 .resx 文件移动到项目的根目录而不是子文件夹中,它会按预期工作。我已经尝试了从子文件夹嵌入的各种方法,但它不再有效。现在我将使用此解决方法,但我怀疑这是 RC2 中的错误。
就像你提到的,我也认为这是一个错误。我猜这么久,该错误位于自动生成的 Designer 工具中。
出于奇怪的原因,以及为什么您的解决方法有效,该工具假定您将所有 resx 文件放在应用程序的根目录中。
这是该工具的输出示例:
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Cosmos.ViewModels.Default", typeof(Default).GetTypeInfo().Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
其中,Cosmos.ViewModels
是程序集名称,但是 .resx 文件都集中在(对于我们当前的解决方案)Resources.da
命名空间中,给出了 [=31 的完全限定命名空间=]Cosmos.ViewModels.Resources.da
.
考虑到这一点,您可以将文件保留在您希望的位置,然后将 Cosmos.ViewModels.Default
的硬编码字符串更改为 Cosmos.ViewModels.Resources.da.Default
.
当然,该工具可能会再次意外删除您的更改。
希望微软能解决这个问题。我在 github 上创建了一个问题,但我认为这个问题实际上应该在核心 cli 中。
MissingManifestResourceException from included assembly although present #1534
我使用的是 MVC Core 1.1.0,我可以在子文件夹中添加资源文件。当您尝试更改没有子文件夹的资源文件的命名空间时,它会抛出错误。所以资源文件命名空间可以和生成时一样。
我刚升级到 Rc2,以前可以用的东西不再用了。我在一个单独的项目中有几个 resx 文件,我使用自定义 class 来访问数据。现在我在 运行 时收到以下错误:
MissingManifestResourceException:找不到任何适合指定文化或中性文化的资源。确保 "GarageWeb.Core.CoreResources.resources" 在编译时已正确嵌入或链接到程序集 "GarageWeb.Core" 中,或者确保所需的所有附属程序集都是可加载且已完全签名的。
编辑:我对此进行了简化并创建了一个控制台应用程序,该应用程序删除了除此处重现错误所需的所有内容外的所有内容:https://github.com/GarageWeb/ResourceTest
这里是访问资源的class:
public class ResourceService : IResourceService
{
private readonly ILoggingService _loggingService;
private readonly ICoreGlobalResourceService _coreGlobalResources;
private readonly ISiteGlobalResourceService _siteGlobalResources;
public ResourceService(ILoggingService loggingService, ICoreGlobalResourceService coreGlobalResourceService, ISiteGlobalResourceService siteGlobalResources)
{
_loggingService = loggingService;
_coreGlobalResources = coreGlobalResourceService;
_siteGlobalResources = siteGlobalResources;
}
public string GetGlobalText(string resourceKey, bool includeBrackets = true)
{
var localizedString = _coreGlobalResources.ResourceManager.GetString(resourceKey);
if (string.IsNullOrEmpty(localizedString))
{
localizedString = _siteGlobalResources.ResourceManager.GetString(resourceKey);
}
if (string.IsNullOrEmpty(localizedString) && includeBrackets)
{
_loggingService.LogInvalidResource(resourceKey);
}
if (includeBrackets)
{
return localizedString ?? "[" + resourceKey + "]";
}
return localizedString ?? resourceKey;
}
public string BuildMessageFromResource(string resourceKey, string placeHolderResourceKey1,
bool includeBrackets = true)
{
var errorString = string.Format(CultureInfo.CurrentCulture, GetGlobalText(resourceKey, includeBrackets),
GetGlobalText(placeHolderResourceKey1, includeBrackets));
return errorString;
}
public string BuildMessageFromResourceAndArray(string resourceKey, string[] arrayOfValues,
bool includeBrackets = true)
{
var placeHolderValue = "";
for (var i = 0; i < arrayOfValues.Length; i++)
{
if (i + 1 == arrayOfValues.Length)
{
placeHolderValue += GetGlobalText(arrayOfValues[i], includeBrackets);
}
else
{
placeHolderValue += GetGlobalText(arrayOfValues[i], includeBrackets) + ", ";
}
}
var errorString = string.Format(CultureInfo.CurrentCulture, GetGlobalText(resourceKey, includeBrackets),
placeHolderValue);
return errorString;
}
public string BuildMessageFromResourceAndTwoArrays(string resourceKey, string[] firstArrayOfValues,
string[] secondArrayOfValues,
bool includeBrackets = true)
{
var placeHolderOneValue = "";
var placeHolderTwoValue = "";
for (var i = 0; i < firstArrayOfValues.Length; i++)
{
if (i + 1 == firstArrayOfValues.Length)
{
placeHolderOneValue += GetGlobalText(firstArrayOfValues[i], includeBrackets);
}
else
{
placeHolderOneValue += GetGlobalText(firstArrayOfValues[i], includeBrackets) + ", ";
}
}
for (var i = 0; i < secondArrayOfValues.Length; i++)
{
if (i + 1 == secondArrayOfValues.Length)
{
placeHolderTwoValue += GetGlobalText(secondArrayOfValues[i], includeBrackets);
}
else
{
placeHolderTwoValue += GetGlobalText(secondArrayOfValues[i], includeBrackets) + ", ";
}
}
var errorString = string.Format(CultureInfo.CurrentCulture, GetGlobalText(resourceKey, includeBrackets),
placeHolderOneValue, placeHolderTwoValue);
return errorString;
}
public string BuildMessageFromResource(string resourceKey, string placeHolderResourceKey1,
string placeHolderResourceKey2, bool includeBrackets = true)
{
var errorString = string.Format(CultureInfo.CurrentCulture, GetGlobalText(resourceKey, includeBrackets),
GetGlobalText(placeHolderResourceKey1, includeBrackets),
GetGlobalText(placeHolderResourceKey2, includeBrackets));
return errorString;
}
public string BuildMessageFromResource(string resourceKey, string placeHolderResourceKey1,
string placeHolderResourceKey2, string placeHolderResourceKey3,
bool includeBrackets = true)
{
var errorString = string.Format(CultureInfo.CurrentCulture, GetGlobalText(resourceKey, includeBrackets),
GetGlobalText(placeHolderResourceKey1, includeBrackets),
GetGlobalText(placeHolderResourceKey2, includeBrackets),
GetGlobalText(placeHolderResourceKey3, includeBrackets));
return errorString;
}
}
这里失败了:var localizedString = _coreGlobalResources.ResourceManager.GetString(resourceKey);
有什么想法吗?有没有一种新的方法来嵌入这些资源?
因此,如果我将 .resx 文件移动到项目的根目录而不是子文件夹中,它会按预期工作。我已经尝试了从子文件夹嵌入的各种方法,但它不再有效。现在我将使用此解决方法,但我怀疑这是 RC2 中的错误。
就像你提到的,我也认为这是一个错误。我猜这么久,该错误位于自动生成的 Designer 工具中。 出于奇怪的原因,以及为什么您的解决方法有效,该工具假定您将所有 resx 文件放在应用程序的根目录中。
这是该工具的输出示例:
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Cosmos.ViewModels.Default", typeof(Default).GetTypeInfo().Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
其中,Cosmos.ViewModels
是程序集名称,但是 .resx 文件都集中在(对于我们当前的解决方案)Resources.da
命名空间中,给出了 [=31 的完全限定命名空间=]Cosmos.ViewModels.Resources.da
.
考虑到这一点,您可以将文件保留在您希望的位置,然后将 Cosmos.ViewModels.Default
的硬编码字符串更改为 Cosmos.ViewModels.Resources.da.Default
.
当然,该工具可能会再次意外删除您的更改。
希望微软能解决这个问题。我在 github 上创建了一个问题,但我认为这个问题实际上应该在核心 cli 中。
MissingManifestResourceException from included assembly although present #1534
我使用的是 MVC Core 1.1.0,我可以在子文件夹中添加资源文件。当您尝试更改没有子文件夹的资源文件的命名空间时,它会抛出错误。所以资源文件命名空间可以和生成时一样。