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

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.

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

Plugin Situation: What to do with dependent libraries?

I have a MEF-based application which uses adapters to process files. It uses configuration files to determine which directories to watch and which adapter to use to process each type of file. Plugins take the form of a .dll that implements a common interface.
Each .dll requires its own set of dependent libaries. For instance, plugin1.dll might need to use apilibrary.dll and xmllibrary.dll. It is also possible that at a later date I might want to add plugin2.dll, and plugin2.dll might use xmllibrary.dll as well. These dependent libraries are updated regularly, so I can't count on plugin2.dll using the exact same version of xmllibrary.dll used in plugin1.dll.
I'd like to compile each plugin to one .dll file that invisibly includes within itself all of its dependent libraries, which seems like one way to solve this problem. Alternately, I'd like to figure out how each .dll file can look for its dependent libaries in a subfolder, which I believe would also reduce the possibility of versioning conflicts. Or maybe there's a dead simple solution to this problem that I haven't even considered (which is always very, very likely).
Any thoughts?
You should probably try to get this to work with standard .NET loading rules. However, if you do need to control exactly how assemblies are loaded and which versions are loaded, this blog post shows how: Using Loading contexts effectively
I guess you need to weigh up deployability vs. maintenance. The simple solution is to use a tool called ILMerge. ILMerge takes your project output and can take other assemblies and merge them together. This enables you to wrap up all of the assemblies that your plugin is dependent on, and merge them into a single assembly. Optionally you can do things like re-signing with your public key, etc. Here is a good read: Leveraging ILMerge to simplify deployment and your users experience by Daniel Cazzulino.
But while that is good, what happens if a new version of the referenced assembly is distributed that corrects bugs in that which you have embedded? By the rules of Fusions assembly loader, when it loads the types from your referenced assembly, it will see that they have already been loaded, so there is no reason for it to load the updated version. This would then mean you need to recompile your plugin and merge the newer referenced assembly again.
My question would be, is it really that important to ensure a specific version is used? If a newer version provides an updated implementation (that doesn't break backwards compatibility) then surely this should benefit all plugins that need to reference it?
As for as how assemblies are loaded in reference to each other, have a read of Understanding .Net Assemblies and References, which is an invaluable piece of information.
MEF uses standard .NET assembly loading, and everything's loaded in a single AppDomain. You have very little control over how dependencies are loaded - as they just get loaded automatically by the CLR when the assembly is injected via MEF. Normal CLR assembly loading rules apply when using MEF, so dependencies will be loaded as if they were a dependency of your application - no matter where they're located or referenced.
For the most part, if the plugins and their dependencies are properly written, you most likely will not need to worry about this. As long as the versioning in the dependencies is correct, it will likely just work.

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

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

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