Tuesday, August 15, 2023

Problem with MissingManifestResourceException for embedded resx files in subfolders

If you worked with .Net applications you most probably know what is embedded resources:

Such resources are embedded directly to output assembly. We may check them e.g. with decompiler:

 

Sometime we may need to change namespace of generated resources: e.g. in above example Foo.resx file is located in Resources sub folder so by default it will generate strongly typed class in namespace TestApp.Resources:

Note also line 42 when it created ResourceManager object - it also uses TestApp.Resources namespace. Now in properties of resx file we will explicitly specify Custom tool namespace = TestApp:

After that namespace of automatically generated class will be changed from TestApp.Resources to TestApp. However ResourceManager will be still created with the same old namespace TestApp.Resources:

We may modify .Designer.cs file manually and change namespace of ResourceManager to TestApp (note that if custom tool will run again it will override manual changes in cs file and they should be done again):

But if we will try to get string from generated class Foo.Bar we will get MissingManifestResourceException:

Unhandled exception. System.Resources.MissingManifestResourceException: Could not find the resource "TestApp.Foo.resources" among the resources "TestApp.Resources.Foo.resources" embedded in the assembly "TestApp", nor among the resources in any satellite assemblies for the specified culture. Perhaps the resources were embedded with an incorrect name.

The problem is that after our changes resx file is still embedded to the assembly as TestApp.Resources.Foo.resources:

In order to fix this error we need to edit csproj file and add LogicalName element under EmbeddedResource element for our resx file with correct name:

<EmbeddedResource Update="Resources\Foo.resx">
  <Generator>ResXFileCodeGenerator</Generator>
  <LastGenOutput>Foo.Designer.cs</LastGenOutput>
  <CustomToolNamespace>TestApp</CustomToolNamespace>
  <LogicalName>TestApp.Foo.resources</LogicalName> 
</EmbeddedResource>

After that resource will be embedded to the assembly with correct name TestApp.Foo.resources:

and exception will gone

No comments:

Post a Comment