I was converting some .NET-3.5-based projects to .NET Framework 4.0 and ran into trouble with assembly-embedded string resources.
The code contains references to resource strings like Resources.ValidationFailedMsg. Resources here is an automatically generated class. It’s fully-qualified name is MyAssembly.Properties.Resources (the assembly name is MyAssembly.dll and, to keep it simple, the root namespace of everything in it is also MyAssembly). The project’s “Properties” folder contains Resources.resx, where the string ValidationFailedMsg is defined (e.g. “Validation failed!”) and the Resources.Designer.cs file is generated from it.
Now let’s run this thing. Here’s what happens:
System.IO.FileNotFoundException : Could not load file or assembly ‘MyAssembly.resources….
Excuse me, what file???
First, I understand the concept of binary .resource files and how there may many such files for many cultures, but let’s get one, default culture to work first. From .NET 2.0 to 3.5- compatible versions of this project, all strings were embedded in the assembly itself, so the framework didn’t even look for them anywhere except MyAssembly.dll. How can I make it look at the assembly and not look at anything else?
Second, I noticed a .resource file in the project’s bin\Debug directory, but it’s named MyAssembly.Properties.Resources.resources, not MyAssembly.resources, and msbuild doesn’t copy it to bin\Debug or anywhere else where MyAssembly is referenced. Is this a useful hint to what may be going wrong here?
Third, I can open a new, empty project in Visual Studio 2010, add Resources.resx under properties, put a string there, reference it in the code as TestProject.Properties.Resources.String1, build, and it works like charm. But in the old project, even readding Resource.resx with its strings doesn’t help.
Can you explain why .NET 4.0 compiles these string into one place and then looks for them in a different place, causing the FileNotFoundException? And what is the proper way to migrate a .NET 3.5-compatible assembly with such embedded string resources to .NET 4.0?
Mystery solved.
.NET (before 4.0) looks for the .resource file first. If the file is not found, it looks inside the assembly to find the requested resource.
Starting with .NET 4.0, if the .resource file doesn’t exist, the framework fires an
AppDomain.AssemblyResolveevent and passes the resource file name in place of the assembly name. (WhyAssemblyResolve? – this is probably a bug.) Only if this event is not handled, does .NET 4.0 look inside the assembly for the resource.As it happened, the application had an AssemblyResolve handler registered. The handler was programmed to locate DLLs and never failed for years until the day of the .NET 4.0 upgrade, when it was asked to locate a nonexistent resource file.