The strange case of localized resources not being loaded

For many years I have used a custom localization approach for my MZ-Tools add-in: instead of using .resx files, I used a single embedded .xml document which had nodes for each term, and in turn each one had children nodes for each language (I currently provide six languages). Then I had some functions to retrieve the required term in the desired language. This approach has some advantages, such a centralized source of resources for localization, less size at run-time, and a simplified setup with no resource dlls to deploy (I am aware that *.resources.dll files can be embedded too, but the approach is tricky).

Recently I wanted to use a web-based platform for localization, and to use .resx files which are the “standard” approach for localization. There are also 3rd party extensions such as ResXManager that allows you to manage localized resources in a centralized way using a grid. For the web platform I decided to use OneSky (it’s great and it allows up to 5 users for free). On this platform you can use tons of formats to upload/download the resources to localize, including of course .resx files. So, finally I had all changes made and a new setup that deploys all the *.resources.dll files:

Resources

The localization worked during development, however it failed when installing the extension with the setup. The MZ-Tools add-in failed for VBA/VB6/VB5, it also failed for VS 2005-2010, and the MZ-Tools package also failed for VS 2012-2015. The strings were always shown in English, the default language. Why? I suspected it was somehow related to obfuscation, which I use in the “Release” configuration (used by the setup) but not in the “Debug” configuration (used during development). Using .NET Reflector I didn’t notice anything wrong with the deployed *.resources.dll files. So, I thought about replacing the installed obfuscated main dll by the original one before obfuscation, but before I had to disable strong name verification because at “Release” configuration you need to use delay signing to use obfuscation, and re-sign after obfuscation. To disable strong name verification you have to execute:

sn.exe –Vr *,<public key token>

Suddenly, before replacing the main dll, all worked. So, the problem was that the *.resources.dll files were using delay signing and .NET was refusing silently to load them. I guess that using the Assembly Binding Log Viewer (fuslogvw.exe) would have revealed this. By the way, you can know if a .NET assembly is using delay signing or not (even if it is set to skip strong name verification) using:

sn.exe –vf <assembly>

So, when a Visual Studio project is set to use delay signing, not only its main output assembly but also its *.resources.dll files lack the strong name, and the build process that you use to sign again the main assembly must re-sign also its *.resources.dll files.