Get assembly's requireed assemblies? - c#

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.

Related

Replacing a base assembly with source code in .NET

Suppose you have an assembly B that references A and you have the source code for the assembly A only. Is it possible to build from source code the assembly A and debug it?
Currently we get this error:
Could not load file or assembly 'name' or one of its dependencies. The
located assembly's manifest definition does not match the assembly
reference.
Is there any way to bypass it?
This will depend on if the original assembly A that is referenced is strongly named. This is a feature where assemblies are signed. Keys for all compile time references are stored in the built assembly, B in your case. When loading assemblies the loader may then verify the signatures of all references to ensure the correct assembly is loaded.
So if strong naming is used it is not easy to replace the assembly A with a newer version without recompiling B. There is however a strong name validation bypass feature for full trust application domains.
If you manage to bypass or disable the strong naming you should simply be able to replace the file in the directory with the new version and attach visual studio.

The system can not find the dll

I converted my console app to Class Library project so that I can use dll again for multiple project. I am getting an error
Could not load file or assembly 'System.Net.Http.Primitives,
Version=1.5.0.0, Culture=neutral, PublicKeyToken=b03f5f711d50a3a' or
one of its dependencies. The system can not find the file
I've already tried the solution mentioned here: Could not load file or assembly System.Net.Http.Primitives. Located assembly's manifest definition does not match the assembly reference.
But no luck. Any suggestion
1- check if you are referencing an assembly which in turn referencing an old version of unity. for example let's say you have an assembly called ServiceLocator.dll which needs an old version of Unity assembly, now when you reference the ServiceLocator you should provide it with the old version of Unity, and that makes the problem.
2- may be the output folder where all projects build their assemblies, has an old version of unity.
you can use FuseLogVw application to find out who is loading the old assemblies, just define a path for the log, and run your solution, then check (in FuseLogvw) the first line where the Unity assembly is loaded, double click it and see the calling assembly, and here you go.
Your problem posted here previously: Could not load file or assembly or one of its dependencies
Please search before rising your question. Thanks
try right click -> Properties -> Build Action -> Embeded Resource should make it work
I will show you clearly the mean of Lucky Lefty. In Solution Explorer, right click on you .dll file and choose properties. The properties pane appears then on Buil Action option, you choose Embeded Resource. After that, you rebuil your solution.
You can view more information from here: http://www.codeproject.com/Articles/528178/Load-DLL-From-Embedded-Resource
Remember: Google search is your best friend.

Chain-referenced assemblies in WPF

today I'd like to know how do you configure your projects in C# WPF which references additional assemblies in a chain. By the "in a chain" I mean something like this:
we have application which refers to assembly Plugin
Plugin assembly refers Resources where resources used by Plugin are located, eg. images
main application does not refers to Resource in any way.
The following image illustrates what I've just said:
The problem is that Resources is not copied to the bin folder of the application, causing Plugin (Ctrl on the image) resources it requires finding failure.
Workaround
There are workarounds for it which are simply to include Resources to references of the main application or use a post-build step and manually copy required files in that step.
Conclusion
Concluding, I'd like to ask how do you deal with that problem. Are the any other solutions besides those I mentioned in workaround section? Am I missing something in the projects' configuration?
Make sure that the output directory in the Plugin project properties is same as the output directory of your application. Otherwise you have to copy files yourself as you do.
Second option would be using embedded resources.
If you load the plugin dynamically from a different folder than the EXE, you can also copy its dependencies to the same folder as the plugin and load those assemblies dynamically, as well. You then need to handle AssemblyResolve so that the already-loaded assemblies will be resolved instead of trying to find new assemblies:
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var domain = (AppDomain)sender;
var assemblies = domain.GetAssemblies();
return assemblies.FirstOrDefault(assembly => assembly.GetName().Name == args.Name.Split(',')[0]);
}
The code above does a version and strong-naming insensitive match; you can implement your own policy here if you want something stricter.

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.

Embedding assemblies inside another assembly

If you create a class library that uses things from other assemblies, is it possible to embed those other assemblies inside the class library as some kind of resource?
I.e. instead of having MyAssembly.dll, SomeAssembly1.dll and SomeAssembly2.dll sitting on the file system, those other two files get bundled in to MyAssembly.dll and are usable in its code.
I'm also a little confused about why .NET assemblies are .dll files. Didn't this format exist before .NET? Are all .NET assemblies DLLs, but not all DLLs are .NET assemblies? Why do they use the same file format and/or file extension?
ILMerge does merge assemblies, which is nice, but sometimes not quite what you want. For example, when the assembly in question is a strongly-named assembly, and you don't have the key for it, then you cannot do ILMerge without breaking that signature. Which means you have to deploy multiple assemblies.
As an alternative to ilmerge, you can embed one or more assemblies as resources into your exe or DLL. Then, at runtime, when the assemblies are being loaded, you can extract the embedded assembly programmatically, and load and run it. It sounds tricky but there's just a little bit of boilerplate code.
To do it, embed an assembly, just as you would embed any other resource (image, translation file, data, etc). Then, set up an AssemblyResolver that gets called at runtime. It should be set up in the static constructor of the startup class. The code is very simple.
static NameOfStartupClassHere()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
}
static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
{
Assembly a1 = Assembly.GetExecutingAssembly();
Stream s = a1.GetManifestResourceStream(args.Name);
byte[] block = new byte[s.Length];
s.Read(block, 0, block.Length);
Assembly a2 = Assembly.Load(block);
return a2;
}
The Name property on the ResolveEventArgs parameter is the name of the assembly to be resolved. This name refers to the resource, not to the filename. If you embed the file named "MyAssembly.dll", and call the embedded resource "Foo", then the name you want here is "Foo". But that would be confusing, so I suggest using the filename of the assembly for the name of the resource. If you have embedded and named your assembly properly, you can just call GetManifestResourceStream() with the assembly name and load the assembly that way. Very simple.
This works with multiple assemblies, just as nicely as with a single embedded assembly.
In a real app you're gonna want better error handling in that routine - like what if there is no stream by the given name? What happens if the Read fails? etc. But that's left for you to do.
In the rest of the application code, you use types from the assembly as normal.
When you build the app, you need to add a reference to the assembly in question, as you would normally. If you use the command-line tools, use the /r option in csc.exe; if you use Visual Studio, you'll need to "Add Reference..." in the popup menu on the project.
At runtime, assembly version-checking and verification works as usual.
The only difference is in distribution. When you deploy or distribute your app, you need not distribute the DLL for the embedded (and referenced) assembly. Just deploy the main assembly; there's no need to distribute the other assemblies because they're embedded into the main DLL or EXE.
Take a look at ILMerge for merging assemblies.
I'm also a little confused about why .NET assemblies are .dll files. Didn't this format exist before .NET?
Yes.
Are all .NET assemblies DLLs,
Either DLLs or EXE normally - but can also be netmodule.
but not all DLLs are .NET assemblies?
Correct.
Why do they use the same file format and/or file extension?
Why should it be any different - it serves the same purpose!
You can embed an assembly (or any file, actually) as a resource (and then use the ResourceManager class to access them), but if you just want to combine assemblies, you're better off using a tool like ILMerge.
EXE and DLL files are Windows portable executables, which are generic enough to accomodate future types of code, including any .NET code (they can also run in DOS but only display a message saying that they're not supposed to run in DOS). They include instructions to fire up the .NET runtime if it isn't already running. It's also possible for a single assembly to span across multiple files, though this is hardly ever the case.
Note ILMerge doesn't work with embedded resources like XAML, so WPF apps etc will need to use Cheeso's method.
There's also the mkbundle utility offered by the Mono project
Why do they use the same file format and/or file extension?
Why should it be any different - it serves the same purpose!
My 2ยข bit of clarification here: DLL is Dynamic Link Library. Both the old style .dll (C-code) and .net style .dll are by definition "dynamic link" libraries. So .dll is a proper description for both.
With respect to Cheeso's answer of embedding the assemblies as resources and loading them dynamically using the Load(byte[]) overload using an AssemblyResolve event handler, you need to modify the resolver to check the AppDomain for an existing instance of the Assembly to load and return the existing assembly instance if it's already loaded.
Assemblies loaded using that overload do not have a context, which can cause the framework to try and reload the assembly multiple times. Without returning an already loaded instance, you can end up with multiple instances of the same assembly code and types that should be equal but won't be, because the framework considers them to be from two different assemblies.
At least one way that multiple AssemblyResolve events will be made for the same assembly loaded into the "No context" is when you have references to types it exposes from multiple assemblies loaded into your AppDomain, as code executes that needs those types resolved.
https://msdn.microsoft.com/en-us/library/dd153782%28v=vs.110%29.aspx
A couple of salient points from the link:
"Other assemblies cannot bind to assemblies that are loaded without context, unless you handle the AppDomain.AssemblyResolve event"
"Loading multiple assemblies with the same identity without context can cause type identity problems similar to those caused by loading assemblies with the same identity into multiple contexts. See Avoid Loading an Assembly into Multiple Contexts."
I would suggest you to try Costura.Fody. Just don't forget to Install-Package Fody before Costura.Fody (in order to get the newest Fody!)

Categories

Resources