Load multiple assemblies - c#

How can I load an assembly using its full display name from a location outside the application's bin path?
Usually one can load an assembly from a custom location with
Assembly.LoadFrom(path);
This works, but it seems that for loading a strong-named assembly I need to specify its full display name such as in
Assembly myDll =
Assembly.Load("myDll, Version=1.0.0.1, Culture=neutral, PublicKeyToken=9b35aa32c18d4fb1");
But the problem here is that this only references assemblies that are in my probing path of my application.
So what if I have an assembly dir1/asm.dll and one assembly dir2/asm.dll and both have a strong name.
How can I load them during runtime?

During Runtime, you can specify additional directories to probe when loading an assembly via the following methods:
AppDomain.CurrentDomain.ClearPrivatePath();
AppDomain.CurrentDomain.AppendPrivatePath();
When the subdirectory names are already known during installation, you can also specify these additional directories in the app.config file in the privatePath attribute of the <probing> element.
Make also sure the file name is correct. When you have
AppDomain.CurrentDomain.AppendPrivatePath("Subdir");
Assembly myDll = Assembly.Load("myDll, Version=1.0.0.1, Culture=neutral, PublicKeyToken=9b35aa32c18d4fb1");
then .net will look for a file named "mydll.dll" in the directory "Subdir" beneath the directory of the executable.

you can load any assembly from its location via loadfile (example here)
if you want to take multiple versions of an assembly consider handling the AppDomain.CurrentDomain.AssemblyResolve (example here)
the examples are from a small open source project, which will load dlls from a seperate a "packages" folder (allowing for packages to have their own copy of a dependency, using the isolated loader)

Related

Assembly.LoadFrom not loading DLL in a different project

I have multiple projects in a given solution.
From ProjectA I pass "myProjectB.dll" as assemblyname to a method call
in ProjectC.
When I execute the following in ProjectC, where assemblyname is "myProjectB.dll"
Assembly assembly = Assembly.LoadFrom(assemblyname);
foreach (Type type in assembly.GetTypes())
{
... my code ...
}
I get the following error
Could not load file or assembly 'file:///C:\MyProjectB\bin\Debug\myProjectB.dll' or one of its dependencies. The system cannot find the file specified.
Please let me know how to pass in the assemblyname properly into Assembly.LoadFrom method call.
How can I provide only the project DLL name and be able to go through the solution and identify the full absolute path for that DLL in the solution at run time. Is it even possible?
Thanks
If the assembly is not located in the exact path as your executable, or in the GAC, you need to give the full path in the LoadFrom method.
For example:
Assembly assembly = Assembly.LoadFrom(#"C:\MyProjectB\bin\Debug\myProjectB.dll");
You can also use relative paths:
Assembly assembly = Assembly.LoadFrom(#"..\..\..\MyProjectB\bin\Debug\myProjectB.dll");

Understanding ASP.NET assembly reference management in Web.config file

I have a simple doubt: I have an external assembly that I want to reference. I have an Asp.Net application. I want to use that assembly in my Asp.Net application.
I add a reference and what VS does is just placing my dll in the Bin subdirectory of my web site.
I thought that VS would have modified my web.config file adding external references...
So does it happen only when referencing assemblies in GAC??? (which makes sense given that public tokens and versions are required).
Thankyou
When the CLR loads your assembly for execution, it checks the assembly's manifest to determine what dependencies are required for it to run. It goes through a series of steps to do this:
Check for redirects - if the assembly is strongly-named, the CLR will first check the appropriate config (app.config, web.config, etc.) to see if there are any binding redirects specified. A binding redirect allows the CLR to say, where I am supposed to load v1.0.0.0, instead load v2.0.0.0. If no binding redirect is found for a strongly-named assembly, it will check a policy file in the GAC, and if no policy file is found, it checks the machine.config. If no binding redirect is specified, the CLR will use the assembly name specified in the calling assembly's manifest to load the assembly.
Check to see if the assembly has already been loaded - the CLR determines if the assembly has previously been loaded, if it has, it uses that same loaded assembly, otherwise it continues...
Load the assembly from the GAC - If the assembly could not previously be loaded and is strongly-named, the CLR will attempt to load the assembly from the Global Assembly Cache.
CodeBase - If the CLR still can't find the assembly, it will use the codeBase path to try and locate the assembly.
Probing - If the CLR still can't find the assembly, it will check the probing path for the assembly. The default probing path is the application base path of the AppDomain into which assemblies are currently being loaded.
(That's all adapted from a great article called Understanding .Net Assemblies and References ).
In the case of your web application, the CLR still does all of the above, but the AppDomain application base path is the /bin folder within your IIS application.

Get assembly's requireed assemblies?

I am loading an assembly X.dll in my program, where X.dll can be anything, and I create an instance of the class X.A_Class. But what if the assembly X requires assemblies A, B, C and D?
How do I detect this?
How do I load them without holding them in a variable?
You can use Assembly.GetReferencedAssemblies as #alexn mentioned, and then use Assembly.Load to load them. Alternatively, you can hook AppDomain.CurrentDomain.AssemblyResolve and load them on demand.
If you do need to iterate them, make sure you do it recursively to get transitive dependencies.
You can get the referenced assemblies for an assembly with the Assembly.GetReferencedAssemblies method.
Refferenced assemblies normally will be loaded automatically (see related messages like How is an assembly resolved in .NET? for starting links).
If you are loading assemblies not from standard locations (like GAC and application's root folder) you may need either setup path to load referenced assemblies from (search for "assembly default load path" - i.e. app config file - http://msdn.microsoft.com/en-us/library/823z9h8w.aspx) or load them yourself from AssemblyReslove event as mentioned in other answers.
The best way to start debugging the issues with loading assemblies is read blogs at: http://blogs.msdn.com/b/suzcook/archive/2003/05/29/57120.aspx (and related posts http://blogs.msdn.com/b/suzcook/archive/tags/loader+debugging+advice/ )
EDIT: folder -> "root folder" + link to config file topic for probing paths.

ASP.NET application reference to assembly in programmatically loaded assembly

My ASP.NET application loads an assembly and creates a class instance from an object within it. The assembly itself has a reference to a dll called "Aspose.Cells.dll" which it can access without any problems and is located on the same path as the assembly file itself. However, when I make a method call to one of its methods I get this error:
Could not load file or assembly 'Aspose.Cells, Version=4.1.2.0, Culture=neutral, PublicKeyToken=9a40d5a4b59e5256' or one of its dependencies.
I figure that I need to make my ASP.NET application reference this DLL as well but everything I've tried so far has failed. The assembly DLL which is loaded is not located within the root of the web application and I'm hoping that it doesn't have to be.
I can load the assembly like this:
Assembly asm = Assembly.LoadFile(#"D:\Dev\EasyFlow\Plugins\ImportExportLibrary\bin\Debug\Aspose.Cells.dll");
But I can not use it like this:
AppDomain newDomain = AppDomain.CreateDomain("testAspose");
Assembly asm = newDomain.Load(System.IO.File.ReadAllBytes(#"D:\Dev\EasyFlow\Plugins\ImportExportLibrary\bin\Debug\Aspose.Cells.dll"));
Is there a better way to do it?
Update:
Thanks for your replies.
I forgot to mention that I cannot copy the assemblies to the bin folder or the GAC because I want it to work as a plugin system where assemblies can be replaced easily by changing the path to assemblies in a configuration file and not having to manually copy files into the main project.
However, the AssemblyResolve event seems interesting and I will give it a try later.
There are a few ways to do this. One way is described in the Microsoft Knowledge Base article
"How to load an assembly at runtime that is located in a folder that is not the bin folder of the application". It provides a pretty good step-by-step method of how to do this.
You can copy the dependent assembly into the Bin folder or install it in the GAC.
I'm thinking you can add assembly references to the web.config, in the <compilation> section, like so:
<compilation debug="true">
<assemblies>
<add assembly="Aspose.Cells, Version=4.1.2.0, Culture=neutral, PublicKeyToken=9a40d5a4b59e5256"/>
</assemblies>
</compilation>
I am not altogether certain this will work, and it may require a corresponding entry to web.config in a <configSections> node under <configuration>.

Trying to load an app through reflection and get error "Could not load file or assembly...The system cannot find the file specified."

The assembly it's trying to find isn't the root assembly - it's a referenced one, but it's in the same folder, and Directory.GetCurrentDirectory() is the folder with all of the files in.
I'm stuck - any suggestions?
You can either:
Create a new AppDomain to load the assembly (and set the AppDomain's base directory to the directory containing all the assemblies).
Attach a handler for AppDomain.AssemblyResolve to help the CLR find the assembly's dependencies.
You might be able to add the directory in question to the list of paths to probe. However, it will need to reside somewhere under your application's directory. See the probe element for more info.
You could try using something like this
string myDll = string.Empty;
string location = Assembly.GetExecutingAssembly().Location;
if (location != null)
{
myDll = string.Format(#"{0}\my.assembly.name.dll", location.Substring(0, location.LastIndexOf(#"\")));
}
This should get physical directory in which the assemblies are running. This could be in the Windows .NET temporary directories. However, because the files are at the same level they should exist there side by side.
If you use assembly.loadfrom you can specify the file path to the assembly.
The load-from context allows an
assembly to be loaded from a path not
included in probing, and yet allows
dependencies on that path to be found
and loaded because the path
information is maintained by the
context.
Executing the program from the folder that has the referenced dll can also solve the problem.

Categories

Resources