Yes, I know this question looks similar to C# - 'Resources' DLL failing to be loaded as it doesn't exist, but my question is about a DLL that I do not own. That other question involves the author's own DLL that they wrote.
EDIT: after solving the problem, it turns out to have been the exact same scenario. I have self-flagged my own question as a duplicate.
I am writing a C# library that uses the Cosmos DB .NET SDK 3.32.2. Sometimes, this library throws an exception because it could not find Microsoft.Azure.Cosmos.Direct.resources.dll
. This file never existed in the first place; the Cosmos.Direct
DLL ships with en-US
invariant culture resources embedded inside the DLL. Yes, I decompiled it to check - Cosmos.Direct
seems to be part of the SDK that the Cosmos team didn't release as open-source.
To be clear, I do not control Microsoft.Azure.Cosmos.Direct.dll
. That is my dependency. FYI, the NuGet package for Microsoft.Azure.Cosmos
ships with four DLLs, one of them being Microsoft.Azure.Cosmos.Direct.dll
.
FooBar.OurCustomExceptionType: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> System.IO.FileNotFoundException: Could not load file or assembly 'file:///C:\Foo\Bar\Microsoft.Azure.Cosmos.Direct.resources.dll' or one of its dependencies. The system cannot find the file specified.
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 Microsoft.Azure.Documents.StoreResult.CreateStoreResult(StoreResponse storeResponse, Exception responseException, Boolean requiresValidLsn, Boolean useLocalLSNBasedHeaders, Uri storePhysicalAddress)
at Microsoft.Azure.Documents.StoreReader.<ReadMultipleReplicasInternalAsync>d__14.MoveNext()
... long stack trace ...
at FooBar.OurCustomCosmosWrapper`1.<GetItemAsync>d__4.MoveNext()
Looking at the stack trace, the library is searching for a "satellite assembly" of resources that never existed, even though the resources are embedded in the DLL.
I have set my own app to use [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)]
in AssemblyInfo.cs, but clearly that is not affecting this Cosmos dependency library. It only affects my own FooBar assembly that takes a dependency on the Cosmos SDK.
How do I force my one of my dependency DLLs (in this case, Microsoft.Azure.Cosmos.Direct.dll) to use its own embedded resources instead of trying to find a separate resources.dll
file that doesn't exist?
I bet this could be one of a few problems:
It was not Cosmos's fault; we actually had an AppDomain.AssemblyResolve handler registered somewhere else that was intercepting assembly loads, even if they were embedded assemblies, and was attempting to load them from a specific location as a .dll file. This file never existed, so it would fail.
That SO post I originally mentioned in my question? C# - 'Resources' DLL failing to be loaded as it doesn't exist
It did in fact solve the problem. Just search your repo for AssemblyResolve
, check to see if a handler function was registered for it, then makes sure that handler returns null
(or nullptr
if in C++) when it encounters one of your embedded resource assemblies.