Cannot load assembly at runtime - c#

This is strange...
In a project of mine I need to load external dll's at runtime. I've done this frequently before and I thought I had stepped on all the mines there where but this one has got the best of me so far.
It's very very basic really. I use Assembly.LoadFrom("c:\\test\\mytestlibrary.dll") but Fusion cannot find the file (I get a FileNotFoundException).
I have examined the fusion logs as usual and it just doesn't make sense. Are there some circumstances that would somehow prevent Fusion from finding a file even when I provide the complete and absolute path to it? I suspected the dll in question needed some other assembly but looking at the fusion logs doesn't indicate this. Besides, the test library references nothing that's not also referenced by the host assembly.
Any suggestions?

Perhaps this blog entry by Suzzanne Cook will provide some clues?
For FileNotFoundException:
At the bottom of the log will be the paths that Fusion tried probing for this assembly. If this was a load by path (as in Assembly.LoadFrom()), there will be just one path, and your assembly will need to be there to be found. Otherwise, your assembly will need to be on one of the probing paths listed or in the GAC if it's to be found.
You may also get this exception if an unmanaged dependency or internal module of the assembly failed to load. Try running depends.exe on the file to verify that unmanaged dependencies can be loaded. Note that if you re using ASP.NET, the PATH environment variable it's using may differ from the one the command line uses. If all of them could be loaded, try ildasm.exe on the file, double-click on "MANIFEST" and look for ".file" entries. Each of those files will need to be in the same directory as the manifest-containing file.
-- http://blogs.msdn.com/b/suzcook/archive/2003/05/29/57120.aspx
IIRC, the fusion log should also show the list of paths sought. Is your path included? Further, is the assembly already loaded as a project reference or otherwise previously in the same app domain?

Related

Resolving .NET assembly name collision

I currently have a .NET application which references "SomePackage.dll" and "SomeUtilities.dll".
SomePackage.dll is contained in a separate folder, and one of the assemblies it depends on is also named "SomeUtilities.dll".
In other words, I added a reference in my project to \somePath\SomePackage.dll, and there exists a file \somePath\SomeUtilities.dll that SomePackage.dll depends on. Since I already have a reference in my project to a assembly called SomeUtilties.dll, I could not add a reference to \somePath\SomeUtilties.dll.
As a result, when I try to run my application and initialize a module in from SomePackage.dll, I receive an error:
Could not load file or assembly 'SomeUtilities.dll..." or one of its dependencies. The located assembly's manifest definition does not match the assembly reference.'
To work around this, I used gacutil in the VS developer command prompt to add \somePath\SomeUtilities.dll to the GAC. Now both assemblies are resolved fine, but I was wondering if there was a better way to resolve this name collision that doesn't involve adding to the GAC. I'm worried about potential issues that may arise with installing into the GAC, and have heard that .NET has the ability to look through certain subfolders to resolve assemblies, but am not sure where to find more on this concept.
You can use bind redirect.
Open the .config file to find the location of < assemblyBinding>
Remove the < assemblyBinding> reference.
Type in Package Manager Console: Add-BindingRedirect.
Windows/.NET has a tool called FUSLOGVW.exe that will help find issues with assemblies. This tool is useful but sifting through the logs is cumbersome. There is an open source tool that is a wrapper around FUSLOGVW.exe and makes it much easier to sift through the data and find the root of the problem. I would use this
https://github.com/awaescher/Fusion

Not finding DLL When Ran as a Startup Program

My program runs perfectly except when it is launched as a startup program. When launched as a start up program it is not able to find a first party DLL (or one of it's dependencies).
I get the following exception:
Could not find file or assembly X or one of it's dependencies: C:\Windows\SysWow64\X.dll
It is looking for the first party DLL in the C:\Windows\SysWOW64\ directory instead of in the local directory C:\Program Files\MyProgram\.
The confusing part is, if I launch the program manually everything works fine.
How do I go about finding the source of this problem? I tried using Fusion Log but it only told me the same thing as the exception: That it was trying to load from C:\Windows\SysWOW64 only.
I read that this can occur when your application uses Assembly.Load - The culprit program does use Assembly.LoadFrom - but again, this works fine except when done at start up.
Furthermore, the culprit program does have some [DllImport] attributes.
The issue was to do with using Assembly.LoadFrom and the current directory at start up.
The Assembly.LoadFrom states that it:
assemblyFile may be absolute or relative to the current directory, and the assembly is loaded into the domain of the caller.
When the program is set as a start up program the current directory is
C:\Windows\SysWOW64 for whatever reason.
As you can demonstrate by outputting Directory.GetCurrentDirectory().
Instead of using Assembly.LoadFrom which does not follow the normal probing I am using Assembly.Load as this searches the normal directories where DLLs are contained.
The load context contains assemblies found by probing: in the GAC, in a host assembly store if the runtime is hosted, or in the ApplicationBase and PrivateBinPath of the application domain. Most overloads of the Load method load assemblies into this context.
The load-from context contains assemblies for which the user provided a path not included in the directories searched by probing. LoadFrom, CreateInstanceFrom, and ExecuteAssembly are examples of methods that load by path.
This also explains why Fusion was telling me it was only searching for DLLs in C:\Windows\SysWOW64 - as that's what LoadFrom does, only searches in the directory given. Which in my case was the current directory.

Why does the assembly reference gets loaded successfully when using MEF?

Contrary to the usual issues of MEF users, I'm not trying to figure out why a dependency of an assembly I load with MEF is not resolved. I am solving the opposite problem - trying to find out why the dependency is loaded.
The situation is that I have an ASP.NET application which uses MEF to dynamically load extension assemblies residing outside the application directory. There may be several versions of the same extension assembly in different directories I probe with MEF, each with its own set of dependencies and these dependencies again may be multiple versions of a single assembly (i.e. extension A.dll, 1.0.0.0 has a dependency D.dll, 1.0.0.0 and an extension B.dll, 2.0.0.0 has a dependency D.dll, 2.0.0.0).
It works in a sense that all the extensions and all their dependencies are loaded correctly. And I don't know why. I have no special settings in my web.config file. Where in the official documentation on assembly resolving does it say that it should work? It doesn't say anything about looking at the same directory the requesting assembly is located at.
I was hoping the Fusion Log Viewer would tell me how the runtime locates the dependencies but even though it shows me the binding requests for all the different versions of a given dependency, when I click on it to see the full log, I only see failed bindings (and yes, I have it set to log all binding requests, not just the failed ones).
Can anyone point me to the part of an official documentation explaining why this scenario works?
The main resolution with MEF is determined by the ComposablePartCatalog used. For example, if you use DirectoryCatalog, all assemblies within the specified directory get probed and found.
By looking at the CompositionContainer, you should be able to find the catalogs that are in place, which in turn should provide some details as to why the parts are composing properly.
It is also possible that your dependencies are being found due to the rules defined in "Other Locations Probed":
If an assembly uses the LoadFrom method to reference another assembly, the calling assembly's location is considered to be a hint about where to find the referenced assembly. If a match is found, that assembly is loaded.
If you are using a DirectoryCatalog to find the assemblies within a directory, it internally loads every assembly within that folder. This will cause all of your dependencies to also be loaded into the process when the DirectoryCatalog is constructed.

Can't use an external DLL : FileNotFoundException

I have 2 projects.
The first one just generates a DLL.
The second one needs the first DLL.
But when I call a method from the DLL, I have a FileNotFoundException, with this message :
BDD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
I'm sure that the file exists.
Where I'm wrong ?
Agree with Kieren (+1). Maybe it is finding your DLL but it requires another dependent DLL that cannot be found. Or is there a signature issue (maybe you are looking for another DLL version, etc...)
To turn on fusion Log (you'll have to create a couple fo registry keys):
BTW, fusion is the DLL that contains the logic to load an assembly (probing for local path and subfolders if specified, looking at the GAC, ...). After running your executable, you'll find a log detailing the issues the CLR has found when loading referenced assemblies (ignore the NativeImage logs, inspect just the Default logs).
Short answer: The DLL needs to be in the same directory as the EXE.
Is this the case?
Could you give the full message - and:
Please bear in mind that the FileNotFoundException could be for a dependency of the referenced DLL, not just the referenced DLL itself.
You might want to turn on assembly-binding log (Fusion log) to see what's going on, if the DLL is indeed present.

.NET Load assemblies at runtime Again

I posted a similar question a time ago. I need to load an assembly at runtime.
This is easy if I know the absolute path of the dll at runtime.
But I dont :( The assembly.Load() or LoadFromFile() fails if the file is not in the application root.
The only thing I have is the dll name. The dll could be located in the root, system32 or in even in the GAC.
Is it possible for .net to automatically determine where the dll is at, like for example :
it should first look in the root. If its not there move on to the system folders, else try the GAC.
EDITED
I am using plug-in architecture. I do not need to register the dll. I have a multi user application. I have a applications table containing information regarding applications. Each application has a dll path associated with it, containing certain algorithms associated with that app. Hope this helps.
I hope you've read up on the following. My suggestion...
How the runtime locates assemblies
You can give Assembly.LoadWithPartialName a whirl.. might work.. it says it will search the application folder and the GAC unlike Assembly.Load. (However its less safe.. coz you might end up with the wrong version of the DLL since you dont specify all 4 parts of the Assembly Name)
Also try AppDomainSetup.PrivateBinPath (AppDomain.AppendPrivatePath has been deprecated in favor of this) to add subfolders of the application root to the list of folders to probe assemblies for. You can also try copying over files from other places into a [AppFolder]\MySandboxForDLLsToLoad, which is added to the PrivateBinPath.
When the current application looks for assemblies, it looks in several locations (bin folder, gac, etc..) if it can not find one, then the developer needs to manually tell the application where to look. You can do this by intercepting the AssemblyResolve event, and using the event args to tell the CLR where your assembly is.
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
....................
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var strTempAssmbPath=
Path.GetFullPath("C:\\Windows\\System32\\" + args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll");
var strTempAssmbPath2=
Path.GetFullPath("C:\\Windows\\" + args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll");
if (File.Exists(strTempAssmbPath))
return Assembly.LoadFrom(strTempAssmbPath);
if (File.Exists(strTempAssmbPath2))
return Assembly.LoadFrom(strTempAssmbPath2);
}
You can hook up into AppDomain.CurrentDomain.AssemblyResolve event and load the assembly for your application manually on demand.
Yes there is a way and it depends on whether your dll is weakly(without a public key token) or strongly(with a public key token) named. If its weakly named and you have added a reference to the assembly with the dll within VS, then VS will first look in the application folder root and if it does not find it, it will then look in the subdirectories that you specify as the value of the privatePath attribute in your XML config file.
If its a strongly named dll, then the CLR will search in the GAC so you need to install the dll in the GAC. The CLR can also look in the application directory if you install an XML config file that has its codeBase element pointing to the dll's path.
To specify an assembly in the GAC you can use the /reference:[DLL name] switch when compiling your assembly.
The dll will be found automatically is it is in some location referenced in the PATH system variable (i.e., system32) or if the dll is registered. You can't find it if it can be anywhere on disk, but no one needs that functionality anyway.
EDIT: can the dll's be registered? how are you getting the assembly name if you don't know of the assembly ahead of time? Are you creating some type of plug-in architecture? I think it would help if you explained your situation a bit more.
EDIT2: If that is the case, why not provide a way for the user to register his or her plug in? You can get all the information that you need from an open file dialog. That or simply make them dump it into a folder that you specify.
You have three options
Install the assembly in the global assembly cache (GAC)
Use an application configuration (.config) file with the tags
Use the AssemblyResolve event
You can find the details here.
The resolution algorithm used by .NET to find the assemblies and their dependents is straight forward.
.NET identifies the required version. Usually the information about the dependant assemblies is present in the application's assembly manifest.
.NET searches GAC (Global Assembly Cache), only if the assembly is strong named.
If not found in GAC, and if a .config file presnt, then .NET searches the location specified in the cofiguration file, else .NET searches directory containing the executable (.EXE)
After this, If the assembly is still not found, the application terminates with error.
Click here for the video explaining the .net resolution algorithm, and click here for a video on late binding assemblies
Register this assembly into the GAC. How to do that
Use this
Assembly.LoadWithPartialName(assemblyName);

Categories