Dynamic assembly loading, memory issue - c#

I'll mostly probably need to load the same assembly dynamically multiple times. My questions are:
Will the assembly be actually loaded only once or multiple times? The assembly itself being a DLL suggests the first option, but who knows :)
I had an experience, that the same types instantiated from the same assembly, but loaded dynamically from two different places were incompatible. Is this also the case with loading this assembly twice from the same place?

It depends on the loading context of the assembly load. That's a hundred dollar word that's hard to explain in an SO answer, Suzanne Cook's blog goes into the concept in detail. In a nutshell, the context permits the CLR to figure out whether an assembly was loaded before and where it should look for dependent assemblies.
It is easier to explain what can go wrong. Both Assembly.LoadFile() and Assembly.Load(byte[]) loads assemblies without a context. With the quirk that this allows an assembly to be loaded more than once since the CLR cannot determine if the assembly that's getting loaded by them was previously loaded. For LoadFile() this is intentional, in very select cases you want to allow to load an assembly again. For Load(byte[]) it is in inevitable accident, the CLR doesn't know enough about the identity of the assembly since it cannot know its display name.
This is almost always bad, types in .NET have an identity that isn't just the namespace name + type name, it also includes the assembly that the type was loaded from. You tend to get hard to diagnose InvalidCastExceptions that read like "Unable to cast object of type Foo.Bar to type Foo.Bar". That leads to clumps of head hair being lost on trying to figure out what that means and what causes it.
Watch out for Assembly.LoadFile(), its name is entirely too innocent looking and it very rarely does what you want it to do. Use LoadFrom() instead. Load(byte[]) is similarly dangerous and a very poor substitute for a proper installer.

You can't load the same assembly multiple times into the same application domain, and unless the assembly has changed it wouldn't make a lot of sense to, either.
If you do want to repeatidly load an assembly then you need to load it into a different appdomain and then unload the appdomain in order to unload the assembly. The reason for this is there is no explicit way to unload an assembly, only an appdomain.

Related

.net automatic assembly resolve loads duplicate assembly

I have an executable that depends on a library. I also have a "loader" application, which loads the executable into a seperate AppDomain (my "sandbox") and runs it there. The library needs initialization from outside the sandbox, so I need to load the library before I load the executable. This works as expected, but when I now load the executable, the library is loaded another time, and the executable uses the uninitialized copy.
This only occurs if I load the library like this:
Assembly.Load(File.ReadAllBytes(assemblyFile.FullName));
instead of this:
Assembly.LoadFrom(assemblyFile.FullName);
However, using LoadFrom locks the file. I need to be able to delete/write the file, because my application needs to be able to reload the entire sandbox and all assemblies in it.
I also tried registering AppDomain.AssemblyResolve, but it is only called if it does not find the file, which isn't exactly what I want ...
Example log output:
Loading library X <- manual load
Initializing library X
Loading executable Y
Loading library X <- bad, i want to use the loaded X!
So my question is: How do I force .net to use the already loaded assembly instead of loading a duplicate?
From the remarks on Assembly.Load(Byte[]):
Note that this method overload always creates a new Assembly object with its own mapping.
You can't use that overload if you want to reuse your loaded assemblies (without extra work anyway - the Framework won't automatically do it for you here).
You might be able to use the Assembly.Load(string) or just Type.GetType(string) methods here, but I suspect that's still going to end up locking files you want to modify. I'm not really sure how to make sense of modifying those files at run time to be honest though - what's the expected behavior if you delete or change a loaded assembly? Reload it? Have the modified code entered into memory?
You might need to create some kind of assembly caching mechanism of your own. If the assemblies aren't that large and you can afford to keep them in memory, it might be something as simple as a Dictionary<string, Assembly> - and just check if the dictionary has your assembly before loading it, otherwise load it using Assembly.Load(Byte[]) the way you are now.
I ended up modifying my AppDomainSetup of the sandbox:
domainSetup.DisallowApplicationBaseProbing = true;
Now, AssemblyResolve will be called everytime (no autodiscover for assemblies). Now I can just load assemblies from a byte[] and cache them (thanks to #DanField who suggested caching assemblies)

Is code executable on loading an assembly into the AppDomain

Is it possible to write code, which will be automatically executed when loading an assembly into an AppDomain with Assembly.Load? I need this information because our PlugIn system loads PlugIns and then check if they are valid, because they contain a signature in an attribute.
EDIT
I want to know whether the creator of the plugin is able to execute code when i am loading the assembly. If this is possible, we got some security issues.
From a security perspective I made the following findings when investigating this issue in depth:
from another question on Stack overflow, Jon Skeet says: "I don't believe there's any way of forcing a method to be run on assembly load"
If this was said by anyone else I would have ignored it, but if Jon Skeet says its impossible, its probably impossible.
Secondly, I tested Module Initializers in depth.
This will only fire code right before a class in the assembly is instantiated.
If no class from the assembly is explicitly instantiated, the Module Initializer will also not fire.
What is possible is if somewhere in your code, or a 3rd parties code that is running in your domain, the code loads and instantiates all classes with a certain Interface or base class or Attribute through out your app domain, and you might not be aware of this code. In such a case, code in the constructors of these classes will fire as soon as they are instantiated.
but other than that, through testing all scenarios and ideas that I could think of, and doing searches across the web, I came to the conclusion that it is not possible to execute code in a assembly, by simply loading the assembly.
The AppDomain.AssemblyLoad Event allows you to handle an event when an assembly is loaded into the AppDomain. You can find an example on the page linked.
Although this not directly answering the question, it does provide a good workaround for the question asked.
If you need to reflect the types in the assembly, while wanting to be 100% sure that no code in the assembly is executed.
you can do this without actually loading the assembly in to your AppDomain by using the Assembly.ReflectionOnlyLoadFrom method.
this will allow you to look at they types in the assembly but will NOT allow you to instantiate any of them, and will also not load the assembly in to the AppDomain.
Look at this example as exlanation
public void AssemblyLoadTest(string assemblyToLoad)
{
var initialAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4
Assembly.ReflectionOnlyLoad(assemblyToLoad);
var reflectionOnlyAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4
//Shows that assembly is NOT loaded in to AppDomain with Assembly.ReflectionOnlyLoad
Assert.AreEqual(initialAppDomainAssemblyCount, reflectionOnlyAppDomainAssemblyCount); // 4 == 4
Assembly.Load(assemblyToLoad);
var loadAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //5
//Shows that assembly is loaded in to AppDomain with Assembly.Load
Assert.AreNotEqual(initialAppDomainAssemblyCount, loadAppDomainAssemblyCount); // 4 != 5
}
If you just need to check information of the assembly like the publicKey, instead of loading the Assembly, load the AssemblyName directly:
AssemblyName an = AssemblyName.GetAssemblyName("myfile.exe");
byte[] publicKey = an.GetPublicKey();
CultureInfo culture = an.CultureInfo;
Version version = an.Version;

Does ReflectionOnlyLoad initialize or otherwise run any code?

For a project I'm working on I have to analyze several dozen assemblies.
It is very important that none of the code contained within these assemblies is actually being run, therefore I looked at Assembly.ReflectionOnlyLoad, as the documentation on MSDN mentions:
Loads an assembly into the reflection-only context, where it can be
examined but not executed. This member is overloaded. For complete
information about this member, including syntax, usage, and examples,
click a name in the overload list.
Now I know regular Assembly.Load runs either the initializers or the constructors of the objects it loads, but am I right in the assumption that this is not the case for ReflectionOnlyLoad, or should I be looking into other ways of achieving what I want?
ReflectionOnlyLoad will indeed forbid any code from the assembly from executing. It also has its own issues - notably, it's not cabaple of loading any dependencies. This can be tricky, since reflecting on a class deriving from a type defined in a different assembly will fail.
As far as I'm aware, Assembly.Load will not run anything in the assembly by default (EDIT: except for the module initializers, which could be abused; if you're not concerned with "hackers", this is not a problem, since normal C# code can't write module initializers, but it can be added in IL, and it might be present in C++/CLI assemblies), until you actually make it do so - for example, trying to get a value of a static field somewhere - but then again, doing that in a reflection only context will cause an exception.
In any case, whether you use ReflectionOnlyLoad or just plain old Load, make sure you're loading the assembly into a separate application domain. This lets you define different security contexts (no full trust for untrusted assemblies) and just as importantly, unload the assembly when you're done with it. If you don't load it in a separate application domain, you're not getting rid of the assembly until you restart your whole application.

Hiding types from being listed in Assembly.GetTypes in .net

Ive been looking everywhere for a possible solution to this but can't seem to find an answer. My issue is that I have a few classes that need to completely hidden from Assembly.getTypes, as I'm writing a plugin for an application, and it's picking up types that I need to remain hidden (this happens even if they are declared as private or internal classes).
anyone know how to either alter what assembly.GetTyes returns, or an ,aficionado attribute that will keep those types from being listed?
This is quite a hack and is very fragile, but could work.
Create 2 assemblies -- one for the plug-in and the second for the other types. The second would be placed in another known directory and loaded dynamically into the first when needed. (For example, via Assembly.LoadFrom.)
The first assembly would then be placed in the plug-in directory and only ever publish its types. This very fragile because you would likely have to hard-code a path to the second assembly and you run the risk of the file getting deleted or moved.
EDIT
#SLaks' comment takes away the fragility of this solution. If you embed the second assembly as a resource and load it at run-time, the app calling Assembly.GetTypes won't see the types you want hidden.
This is not possible.
Sorry.
Code that calls Assembly.GetTypes() should typically filter for only public types.
Welcome to managed code. Complete type information is necessary to .NET's type verifier. Only native code can be hidden from .NET metadata, and then you give up the portability and permissions supported by pure MSIL.

Unable to cast transparent proxy to type from AppDomain

I'm trying to create an object in an appdomain:
var type = typeof (CompiledTemplate);
var obj = (CompiledTemplate) domain.CreateInstanceAndUnwrap (
type.Assembly.FullName, type.FullName);
However, I always get the following error:
Unable to cast transparent proxy to type 'Mono.TextTemplating.CompiledTemplate'.
I'm running on .NET 4.0, not Mono, despite what the namespace might suggest :)
As far as I know, this error happens when .NET thinks that the Type & Assembly do not exactly match in the two domains. However, when debugging, the FullName and Location are identical. Only the Assembly.Codebase property differs - in the child AppDomain its extension is uppercased to "DLL" for some reason.
I've tried adding an AssemblyResolve handler to the AppDomain, which uses Assembly.LoadFrom to load the filename explicitly, but the CodeBase's extension still gets uppercased. Since the original assembly was also loaded with Assembly.LoadFrom (via Mono.Addins), the difference between the CodeBase values seems very strange.
Any suggestions for fixing or working around this problem?
Could you be running into an issue with assembly load contexts?
(e.g. see here)
You have a type that's clearly in the load context (because you're using typeof(CompiledTemplate)), but you're saying that the type in the secondary AD is loaded into the load-from context...
Did you check with fuslogvw to determine exactly what assemblies are being loaded? The fuslog trace will also tell you if the assemblies are being loaded into different contexts.
Perhaps you can use the dynamic keyword instead of casting it to a specific type:
var type = typeof (CompiledTemplate);
dynamic obj = domain.CreateInstanceAndUnwrap (
type.Assembly.FullName, type.FullName);
That might at least give you a workaround to the problem. Of course, the potential drawbacks will be not having compile time checking and/or slower performance. However, these might be negligible trade-offs depending on your situation.
A second copy of the assembly is, indeed, being loaded into memory as it is.
An instance of a type in the runtime is specific to the instance of the assembly loaded - so even if the same DLL file is loaded in a second time, the types are not considered to match.
This is a typical problem when "DLLHell" is extended into the "GACAndDLLHell". "GACONLYHeaven" is a better place ... :).
That the filenames are subtly different (the .DLL extension has a different case) implies that the same DLL is being loaded from two places (that is: the GAC is case-insensitive/always lower case on filenames IIRC).
An abstract class or, preferably, an interface is what you need here.
If you can't make changes to the code base I would, first, make very sure that the DLL exists in only 1 place on the drive (or 0 places on the drive if it is being loaded from the GAC). A copy of the DLL that contains the type: 'CompiledTemplate' in your app /bin folder would be a real culprit ...?
Is this new code or existing code that is now failing for some reason?
I have a WCF net named pipes application that uses a callback (duplex) architecture.
I got this error because my service interface's [ServiceContract] was annotated with the wrong callback.

Categories