Localization in separate project Asp.net Core MVC

孤人 提交于 2019-12-10 12:55:51

问题


I just upgraded to Rc2 and what used to work no longer does. I have a couple of resx files in a separate project and I use a custom class to access the data. Now I get the following error when running it:

MissingManifestResourceException: Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "GarageWeb.Core.CoreResources.resources" was correctly embedded or linked into assembly "GarageWeb.Core" at compile time, or that all the satellite assemblies required are loadable and fully signed.

EDIT: I simplified this and create a console app that is stripped of everything but what is required to reproduce the error here: https://github.com/GarageWeb/ResourceTest

Here is the class that accesses the resources:

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;
    }
}

It fails here: var localizedString = _coreGlobalResources.ResourceManager.GetString(resourceKey);

Any ideas? Is there a new way to embed these resources?


回答1:


So, if I move the .resx files to the root of the project instead of in a sub-folder, it works as expected. I have tried every way to embed from a sub-folder and it no longer works. For now I will use this workaround, but I suspect this is a bug in RC2.




回答2:


Like you mentioned, I also believe this is a bug. I would guess so long, that the bug is located in the auto-generate Designer tool. For odd reasons, and why your workaround works, the tool assumes that you put all resx-files in the root of your application.

Here is an example of the output of the tool:

[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;
        }
    }

Where, Cosmos.ViewModels, is the assembly name, but the .resx files are all gathered in (for our current solution) the Resources.da namespace, giving a fully qualified namespace of Cosmos.ViewModels.Resources.da.

With this in mind, you can keep the files where you wish, and then change the hardcoded string of Cosmos.ViewModels.Default to Cosmos.ViewModels.Resources.da.Default.

Of course with the risk of the tool accidentally removing your changes again.

I hope Microsoft will fix this. I have created an issue on github, but I think the issue should actually be in core cli.

MissingManifestResourceException from included assembly although present #1534




回答3:


I am using MVC Core 1.1.0, I am able to add the resource file in sub folder. when you try to change the namespace of the resource file without sub folder, then it throws error. So the resource file namespace cane be same as when it got generated.



来源:https://stackoverflow.com/questions/37360068/localization-in-separate-project-asp-net-core-mvc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!