7

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?

mrfleck
  • 311
  • 2
  • 9
  • Did you embed the resource files [as outlined here](https://github.com/aspnet/Announcements/issues/175)? – poke May 21 '16 at 07:26
  • `"buildOptions": { "embed": { "includeFiles": [ "Resources/CoreResources.resx", "Resources/SiteResources.resx" ] } }`This is where I embedded the files. This is in the referenced project.json – mrfleck May 21 '16 at 07:53
  • Did you specify the default culture for the assembly which holds the ressources? – Durgil May 21 '16 at 08:05
  • I set the default culture in the web app that references the class library where these resources exist. I am not sure I know how to set a default culture in the class library itself. – mrfleck May 21 '16 at 08:16
  • Here is where I set the language and embed in the class library:` "language": "en-US", "buildOptions": { "embed": { "include": [ "Resources" ] } }` – mrfleck May 21 '16 at 17:23
  • Do you have any solution for asp.net core 1.0.0? Now I have the same issue but I can't make it work even from the project root. – Dmitry Sikorsky Sep 12 '16 at 15:49
  • I am using 1.0 with no issues. I left the files at the root of my project. – mrfleck Sep 14 '16 at 09:26

3 Answers3

7

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.

mrfleck
  • 311
  • 2
  • 9
  • Have you reported it to the AspNetCore-team? – gimlichael Jun 02 '16 at 15:09
  • 1
    I did add an issue here: https://github.com/aspnet/Localization/issues/245 looks like they have logged it as a tooling issue here: https://github.com/aspnet/Tooling/issues/532 – mrfleck Jun 04 '16 at 02:30
3

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

gimlichael
  • 1,315
  • 1
  • 15
  • 28
0

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.

Nizam Deen
  • 161
  • 1
  • 6