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?
Localizing Static Text If a page includes static text, you can use ASP.NET localization by including it in a Localize control, and then using explicit localization to set the static text. The Localize control renders no markup; its only function is to act as a placeholder for localized text.
Globalization is the process of designing the application in such a way that it can be used by users from multiple cultures across the globe. Localization, on the other hand, is the process of customization to make our application behave as per the local culture.
Resources in . resx files. Unlike text files, which can only store string resources, XML resource (. resx) files can store strings, binary data such as images, icons, and audio clips, and programmatic objects.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With