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;
Related
Is it possible to run some code when an assembly is loaded, without doing anything specific in the loading code? What I am looking for is like a static constructor on a type.
Eg:
Assembly A does not know about Assembly B, but B does know about A. Assembly A needs to know certain things about B if B is loaded. When Assembly B is loaded by the runtime (referenced, or explicit), I want a piece of code (static method or attribute) to be executed that calls a method in Assembly A.
The root cause of this problem is unknown types being encountered when serializing a type in A that contains types from B not known at compile time as interfaces are used.
The CLR supports module initializers. You'd have to hack C++/CLI code or ilasm.exe to use them.
UPDATE: directly supported in C# as well since .NET 5 with the [ModuleInitializer] attribute
You can use static constructors in .Net, but unfortunately they don't do what you want. Static constructors are only executed just before a type is used. See http://msdn.microsoft.com/en-us/library/k9x6w0hc(VS.80).aspx for details.
You might get some mileage from subscribing to your AppDomain's AssemblyLoad event. See http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyload.aspx.
In your event handler you could reflect on the newly loaded assembly, and get it to execute whatever code you like.
There are 3 options to initialize a .NET Assembly:
You write a static function Init() or Main() in your Assembly to be initialized and call this function by reflection from the C# code that loads this Assembly.
Write a Managed C++ Assembly where you put your code in DllMain(). Be careful because your code will be executed in the Loader Lock where several things are forbidden (like loading other DLL's,...). But you can start a new thread that does ANY initialization stuff. (About LoaderLock:
https://msdn.microsoft.com/en-us/library/ms173266.aspx) (About
DllMain:
C# to C++/CLI to C DLL System.IO.FileNotFoundException)
You compile a pure C# Assembly and modify the compiled DLL to add a module initializer code like explained here:
http://einaregilsson.com/module-initializers-in-csharp/
The disadvantage of this method is that the initialization function is not called immediately when the assembly is loaded into the process. But it is called before anything else in the assembly is first accessed.
(edit - applies to C#; for a C++ approach, see this answer)
Basically, no: you can't. This would be a huge attack surface, and isn't allowed. You might want to put a static ctor on some of the B types that ensure the init code is executed, but that is about it...
You should probably revisit your serialization approach to mitigate this problem. If you serialize using ISerializable and the SerializableAttribute attribute, you can make it such that the serialization graph will load assembly B when necessary without assembly A ever having to explicitly know about assembly B.
Using a mixed assembly you can get DllMain to run on an assembly load.
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.
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.
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.
I'm trying to load assemblies in a separate app domain, but am running into a very strange problem. Here's some code:
public static void LoadAssembly(string assemblyPath)
{
string pathToDll = Assembly.GetCallingAssembly().CodeBase;
AppDomainSetup domainSetup = new AppDomainSetup
{
PrivateBinPath = pathToDll
};
AppDomain newDomain = AppDomain.CreateDomain("AssemblyLoader",null,domainSetup);
AssemblyLoader loader = (AssemblyLoader)newDomain.CreateInstanceFromAndUnwrap(
pathToDll,
typeof(AssemblyLoader).FullName);
}
AssemblyLoader is another class in the same assembly as this one, and it inherits from MarshalByRef, however for some strange reason, I get a cast exception every time I try to run this. I even hardcoded the path to the DLL instead of using GetCallingAssembly().CodeBase yet I keep getting this exception.
I understand it's hard to answer a question like this without actually seeing it and having more information, but maybe someone has run into a similar situation and would know the common "gotchas" and what I should look out for.
EDIT: The reason I don't want to load it directly is because this is just part of the code. The ultimate goal is that this class will have a method that load assemblies, gets their GUID and some other info about them and stores them in a database for a project I'm working on. Therefore, if I load this assembly in a separate app domain, I can load the others there too and then unload the app domain. No point in having all these assemblies loaded for the duration of the app, if I only need that data.
(EDIT: after reading the exception given, changing answer completely)
It appears the problem is the CreateInstanceFromAndUnwrap call, which uses the LoadFrom semantics of 'pathToDll'. Suzanne Cook detailed the possible sticking point on her blog where your original AppDomain tries to call Load("SomeAssembly, [...]") as opposed to LoadFrom("pathToDll") when trying to resolve the type in question.
Her advice was to hook the AssemblyResolve event on the current domain to do the correct LoadFrom in order to get the type. A little bit of targetted googling brings up a possible solution to the problem based on Suzanne's suggestion.
I don't believe the PrivateBinPath configuration is necessary, beyond that you don't need to use the Path to the DLL, but rather the Assembly's fully qualified name for the first parameter; try:
AssemblyLoader loader = (AssemblyLoader)newDomain.CreateInstanceFromAndUnwrap(
typeof(AssemblyLoader).Assembly.FullName,
typeof(AssemblyLoader).FullName);
There's a lot of good information for what you're trying to do here: How to load a .NET assembly for reflection operations and subsequently unload it?
Check out this article.
Using the code in that article I got a cross app-domain object. I abstracted things a bit with generics and have three assemblies. (i.e. 1 defining the interface, 1 defining the plugin implementation, and the main program which tells the generic what to load.) The original articles code is easy to follow.