Why would I use Assembly.LoadFile in lieu of Assembly.LoadFrom? - c#

It's my impression that Assembly.LoadFrom uses the ApplicationBase and PrivateBinPath. It also my impression that Assembly.LoadFile does not.
Why would anyone want to use LoadFile? In other words, if my understanding is correct, why would anyone want to NOT use the ApplicationBase and PrivateBinPath?
I'm working with some existing code, which uses LoadFile, and I don't understand why it would do so. LoadFile apparently does not load dependencies from the same directory. The LoadFrom method does load dependencies (From the doc: The load-from context...allows dependencies on that path to be found and loaded because the path information is maintained by the context.) I'd like to convert it from using LoadFile, to use LoadFrom.
What is likely to break, if anything, if I replace LoadFile with LoadFrom?
Even if it iss benign, it may be that I cannot do the replacement, just based on project schedules. If I cannot replace LoadFile with LoadFrom, is there a way to convince assemblies loaded with LoadFile to load dependencies? Is there a packaging trick I can use (embedded assembly, ILMerge, an AssemblyResolve event, something like that) that can allow an assembly loaded with LoadFile to also load its dependencies?

Be careful - these aren't the same
thing.
LoadFrom() goes through Fusion and can
be redirected to another assembly at a
different path but with that same
identity if one is already loaded in
the LoadFrom context. LoadFile()
doesn't bind through Fusion at all -
the loader just goes ahead and loads
exactly* what the caller requested. It
doesn't use either the Load or the
LoadFrom context.
http://blogs.msdn.com/b/suzcook/archive/2003/09/19/loadfile-vs-loadfrom.aspx

In addition to Madhur Ahuja's answer, note that in most cases it is actually Assembly.Load that you'd want to use.
http://blogs.msdn.com/b/suzcook/archive/2003/05/29/57143.aspx

Related

C# Load different versions of assembly to the same project

I'm creating some tool what performs several operations like NUnit.
Inside this tool I open .dll assembly and invoke methods form it to run some test.
Everything is going OK till the time I need to reload .dll withour program restart. The idea is that when tool is run we copy required assembly to some temporary folder and invoke from there. If I need to reload I copy another one to another temporary folder and try to load newly copied from another folder and load to previous assembly object
ExecutingAssembly = Assembly.LoadFrom(AssemblyFullPath);
But my problem is that after I change AssemblyFullPath to new one and call Assembly.LoadFrom it returns just old assembly what was loaded first time but not the second one!
Maybe the problem is that we cannot load several assemblies with different versions? What is the solution?
The CLR does support loading multiple versions of strongly named assemblies into the same AppDomain. This only works though if your assemblies are strongly named and each one has a different version than the other.
I'm guessing it's more likely that you are dealing with unsigned assemblies. If that is the case then what you're asking for isn't really possible. Once a given assembly is loaded into an AppDomain it will remain there until the AppDomain is unloaded. To get this to work you will have to abstract out all of the work around the loaded assemblies into a separate AppDomain and use a new AppDomain for every assembly
To expand on JaredPar's answer, you will need to create a new AppDomain and use Remoting to communicate between the two.
Check out http://msdn.microsoft.com/en-us/library/kwdt6w2k(v=vs.85).aspx to help get you started.
Try like this:
string dllFile = "C:\\sample.dll";
Assembly asmLoader = Assembly.LoadFile(dllFile);
Type[] types = asmLoader.GetTypes();
Since all resources from the assembly cannot be reloaded/replaced it's assembly resources while application is still running. It will only be replaced/removed when application is unloaded or the that Assembly that holds it.
Use LoadFile() method. Hope it helps.

How are assemblies loaded into the AppDomain?

What determines when and if an assembly gets loaded into the AppDomain.
I guess I am trying to understand if:
I am guaranteed that all project referenced assemblies will be
loaded at the start of my application.
If not when exactly do
they get loaded? Is it going to be the first time I use a
class/function from that assembly?
Is there a way to tell at
compile time if an assembly must be loaded first, before execution
of the first line in my code? (I know I can use reflection, but I
want to know if I can configure this at compile time)
Assuming I
can control when an assembly gets loaded, what about the dependent
assembly? Can I tell the execution to only load up to 1st/2nd degree
and let the rest be loaded dynamically?
no, you are guaranteed the opposite: only assemblies directly needed at start are loaded.
yes, there will be attempt to load assembly as soon as some class will require type information from that assembly or code that needs that assembly will be JITed.
no, there is no way at compile time to force assembly load sequence short of referencing something from each assembly in your Main (note that usually goal is opposite - to delay loading of as many assemblies as possible to speed up loading of an app).
no, you can't control automatic loading (as Simon Edström points out there Assembly Resolve event fired when CLR decides it needs an assembly). You can always pre-load assemblies yourself if you know dependencies.
Note: assemblies don't "depend" on each other directly, just classes/methods in each depend on each other.
I don't know the details but I know that there is event thorwn when an assemblies can't be loaded. So I guess they are loaded at runtime and you could add routines to it.
I think this will help you a bit about Assembly Resolve http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve.aspx
And this about Assembly Load Events http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyload.aspx

Issue with AppDomain.CreateInstanceFromAndUnwrap

I'm using AppDomain.CreateInstanceFromAndUnwrap() to create an object in a different AppDomain. I couldn't get it to work because it kept throwing the following error at me:
Could not load file or assembly 'COMon, Version=2.0.4960.27874, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The module was expected to contain an assembly manifest.
However, I found that it is because it tries to load my DLL (which has the same name as my .NET assembly).
This is how I call the method:
_script = (Script)_appDomain.CreateInstanceFromAndUnwrap(Assembly.GetExecutingAssembly().Location, "COMon.Scripting.Script");
It works fine as long as there isn't a native DLL file with the same name as my .NET assembly. Why does this happen when I'm passing it the full path and filename of my .NET assembly?
when I'm passing it the full path and filename of my .NET assembly?
That's not how the method works. The first argument is the display name of the assembly. It is not a file name. The MSDN article recommends that you take a look at Assembly.FullName to learn more about display names.
So the normal CLR search rules will be in effect for finding the assembly. It will look in the GAC first, then in the probing path for the AppDomain. With a quirk that you didn't count on, the CLR does not pay attention to the filename extension for a file. The display name for an assembly doesn't specify it. So it considers an EXE and a DLL equivalent. Something you can see back in the trace for Fuslogvw.exe, the utility you always want to use when you have trouble like this. And in other places, adding a reference to an EXE works fine for example.
So it finds COMon.exe and that's a kaboom, it is not a managed assembly.
It isn't that clear what the proper workaround might be in your case, other than simply renaming the assembly. When you tinker with AppDomains then you typically also want to use AppDomainSetup and set the ApplicationBase or PrivateBinPath property.

Add DLL programmatically at runtime

Using C#, I create a DLL at runtime and now I want to add it as a reference to my project at runtime.
I tried using the LoadFrom method, but it doesn't work.
How can I do this?
First you should load the dll
Assembly assembly = Assembly.LoadFrom("dllPath");
Then you may need to add the assembly to the app domain
AppDomain.CurrentDomain.Load(assembly.GetName());
After that you can load any type from this assembly
Type t = assembly.GetType("typeName");
Then using reflection you can execute methods on this type
Note that you may need to add the below in the configuration file.
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="dlls folder"/>
</assemblyBinding>
</runtime>
LoadFile vs. LoadFrom
Be careful - these aren't the same
thing.
LoadFrom() goes through Fusion and can
be redirected to another assembly at a
different path but with that same
identity if one is already loaded in
the LoadFrom context. LoadFile()
doesn't bind through Fusion at all -
the loader just goes ahead and loads
exactly* what the caller requested. It
doesn't use either the Load or the
LoadFrom context. So, LoadFrom()
usually gives you what you asked for,
but not necessarily. LoadFile() is for
those who really, really want exactly
what is requested. (*However, starting
in v2, policy will be applied to both
LoadFrom() and LoadFile(), so
LoadFile() won't necessarily be
exactly what was requested. Also,
starting in v2, if an assembly with
its identity is in the GAC, the GAC
copy will be used instead. Use
ReflectionOnlyLoadFrom() to load
exactly what you want - but, note that
assemblies loaded that way can't be
executed.)
LoadFile() has a catch. Since it
doesn't use a binding context, its
dependencies aren't automatically
found in its directory. If they aren't
available in the Load context, you
would have to subscribe to the
AssemblyResolve event in order to bind
to them.
ref Suzanne Cook's .NET CLR Notes
Use Assembly.LoadFile method and then run code inside it using reflection.
Actually Assembly.Load is usually what you'd want, not LoadFrom and not LoadFile:
Which context is right for you? In
general, I strongly recommend that you
use the Load context whenever possible
http://blogs.msdn.com/b/suzcook/archive/2003/05/29/57143.aspx
You cannot add dll to a project when project is already running. However, you can load the dll using Assembly.LoadFrom( filename). Normally such scenerio is used for SOA or plugin based projects. You can use interface to specify the type structure and load the dll and use it.
You could use the Assembly.LoadFrom method to dynamically load an assembly at runtime.
This is very simple in .NET: http://msdn.microsoft.com/en-us/library/1009fa28.aspx

Can Mono.Cecil modify code already loaded in the AppDomain?

I want to add some behavior to a certain class at runtime. I know how to subclass at runtime using Reflection.Emit but that's not enough. Depending on some external configuration I need to inject opcodes in a method on a type T so all classes that inherit from it automatically gain this behavior. (I can't use the .NET Profiling API).
Can something like this be done with Mono.Cecil?
If it isn't possible to modify code on a loaded assembly, it is fine If I can make the modifications before the assembly is loaded and then load the modified assembly in memory, but I don't know how I can control assembly loading.
Nope, Cecil can not modify a loaded assembly. You have to instrument assemblies before they are actually loaded.
You don't have much control over how assemblies are resolved. You can hook into AppDomain.AssemblyResolve if you hide the assemblies in a private folder of yours, and instrument then before loading them.
As JB Says above-
You can create a Resolve Event handler - which would be like PSeudoHooking.
And before the assembly is loaded, you make your changes, and then once the changes are done, the Resolve Assembly then continues on to load the changed assembly.
I use this method for resolving Embedded Dll's from Memory Streams.

Categories

Resources