I'm running into an issue where .NET appears to be loading the incorrect resource file, and I haven't found any resources online that have run into a similar problem. This has so far only occurred on a backend server when we are trying to get info to send in an e-mail. The culture on the server this is running on is en-US.
Here is the (slightly edited) stacktrace I'm getting:
Could not find file ''C:\Customer\App\SubDir1\SubDir2\SubDir3\ClassLibrary.resources.dll''.
mscorlib
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at <Custom Wrapper for Assembly Loading>
at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalGetSatelliteAssembly(String name, CultureInfo culture, Version version, Boolean throwOnFileNotFound, StackCrawlMark& stackMark)
at System.Resources.ManifestBasedResourceGroveler.GetSatelliteAssembly(CultureInfo lookForCulture, StackCrawlMark& stackMark)
at System.Resources.ManifestBasedResourceGroveler.GrovelForResourceSet(CultureInfo culture, Dictionary`2 localResourceSets, Boolean tryParents, Boolean createIfNotExists, StackCrawlMark& stackMark)
at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo requestedCulture, Boolean createIfNotExists, Boolean tryParents, StackCrawlMark& stackMark)
at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)
at System.Resources.ResourceManager.GetString(String name, CultureInfo culture)
at Project.ClassLibraryResources.SubNamespace2.get_Unit()
We do have resources (two of them in ClassLibrary.dll, under different namespaces), but they are embedded in the DLL, so the ClassLibrary.resources.dll file doesn't exist.
We do not have a .config file that is changing where the resources are searched for, so we don't have it looking for the satellite assembly (which would be ClassLibrary.resources.dll).
Other resources seem to be loaded successfully, and this problem only started after we upgraded to .NET 4.5.2, with no code changes for a few years now done to the DLL that is failing.
Based on the comment at the top found here, I've been trying to use PerfMonitor to trace the resource manager's events to see what it is trying to do, but I haven't had any luck getting that to work so far. I've also been mentally running through the code in that file linked to see what could be going on, but it hasn't been too fruitful.
I have modified the function that tries to access the Unit resource to print out the current thread's culture, and it prints out en-US as expected.
edit: After running it through fusionview logger, I see that it first tried to load the resource under the en culture, and then again under the en-US culture. It checks the application's config file, does not find a host config file, and checks the machine config file. None of these tell resources to look for satellite assemblies. end edit.
Second edit: I also want to re-iterate that we do have a custom assembly resolver/loader. It checks that the file exists, and if so, does Assembly.LoadFrom() on it. If it does not exist, it checks in a second probable location and tries to do a Assembly.LoadFrom() on that. This is failing right before the second Assembly.LoadFrom, when we are opening the file stream. I realize we should probably just change this to use config files to change where to look. I do not think that this is the problem though. End second edit.
What could be causing this error? Is there a better way to access the trace details for ResourceManager?
Any pointers would be greatly appreciated!
The stack trace indicates you're calling a GetString
overload with a CultureInfo
. Exactly what value is being passed in for Culture? Why not call the GetString overload without a Culture?
Have you specified a NeutralResourcesLanguageAttribute on your assembly?