Assembly/DLL loading - c#

I am using a shared DLL. In my Main() I add a handler to AppDomain.CurrentDomain.AssemblyResolve which loads the DLL. This works for some of my programs, others crash before even getting into Main() with a System.IO.FileNotFoundException (it could not locate the DLL file).
Does anybody know why some of my programs try to load the DLL before getting into Main() and others do not? What must I change to prevent the loading of the DLL before reaching Main()?

I have made a repro. As stressed, it is important that you provide a minimal, reproducible example.
It involves a public enum property (Address.All in your case). When I deploy this program and remove the shared DLL, this throws without invoking my event handler:
public class Program
{
public static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolveHandler;
Console.WriteLine("In Main()");
_ = new Foo();
}
private static Assembly AssemblyResolveHandler(object sender, ResolveEventArgs args)
{
throw new NotImplementedException("I'm afraid I can't do that, Dave.");
}
}
public class Foo
{
public Foo()
{
Console.WriteLine("In Foo constructor");
}
public SharedClassLibrary.SharedEnum Unused { get; set; }
}
The shared class library consists of just this:
namespace SharedClassLibrary
{
public enum SharedEnum
{
Zero = 0,
One = 1
}
}
Running this program without the shared DLL present throws a FileNotFoundException complaining about a missing DLL even before entering the Main() method.
So the solution is to have the assembly next to your executable, I don't know why you want to involve your own assembly loading code.
The cause is the JIT, wanting to know everything about the types used within the Main() method. This type Foo is used, and in order to instantiate it, the runtime has to know everything about Foo, among others to be able to allocate memory for the instance.
Part of Foo is an enum, and since enums can inherit from various numeric types with varying sizes (one byte or more), the runtime wants to look up the enum's definition, hence has to load the assembly.
The workaround is to instantiate your form in a new method:
public static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolveHandler;
Console.WriteLine("In Main()");
RunApplication();
}
private static void RunApplication()
{
_ = new Foo();
// or in your case, Application.Run(new MainForm());
}
This shows that my custom assembly resolver is hit:
In Main()
Unhandled exception. System.IO.FileLoadException: Could not load file or assembly 'SharedClassLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Not implemented (0x80004001 (E_NOTIMPL))
File name: 'SharedClassLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
---> System.NotImplementedException: I'm afraid I can't do that, Dave.

Related

Load same assembly second time with clean static variables

I have a .dll library, which I cannot modify, with classes which uses many static variables and singleton instances.
Now I need a second instance of all these classes and I need some solution which would isolate static variables between instances of some class without altering any other properties of the assembly.
Loading the same assembly second time doesn't actually load it again, but I found that reading it to byte array and then loading it, actually solves half of the problem:
lib.dll:
namespace lib
{
public class Class1 : ILib
{
private static int i;
public int DoSth()
{
return i++;
}
public string GetPath()
{
return typeof(Class1).Assembly.Location;
}
}
}
app.exe:
namespace test
{
public interface ILib
{
int DoSth();
string GetPath();
}
class Program
{
static void Main()
{
var assembly1 = Assembly.LoadFile(Path.GetFullPath(".\\lib.dll"));
var instance1 = (ILib)assembly1.CreateInstance("lib.Class1");
Console.WriteLine(instance1.GetPath());
Console.WriteLine(instance1.DoSth());
Console.WriteLine(instance1.DoSth());
var assembly2 = Assembly.LoadFile(Path.GetFullPath(".\\lib.dll"));
var instance2 = (ILib)assembly2.CreateInstance("lib.Class1");
Console.WriteLine(instance2.GetPath());
Console.WriteLine(instance2.DoSth());
Console.WriteLine(instance2.DoSth());
var assembly3 = AppDomain.CurrentDomain.Load(File.ReadAllBytes("lib.dll"));
var instance3 = (ILib)assembly3.CreateInstance("lib.Class1");
Console.WriteLine(instance3.GetPath());
Console.WriteLine(instance3.DoSth());
Console.WriteLine(instance3.DoSth());
Console.Read();
}
}
}
this returns:
C:\bin\lib.dll
0
1
C:\bin\lib.dll
2
3
0
1
Static variables got restarted but unfortunately the next problem is that assembly location which is used within the library is empty.
I would like to avoid loading the library to different AppDomain because it creates too many problems with cross domain code; some classes are not serializable.
I would like to avoid physically copying the library on disk.
I would like to avoid IL weaving and using Mono.Cecil or similar because it's an overkill.
Loading assembly into separate AppDomain or separate process are only sensible options you have. Either deal with cross-domain/cross-process communication or get version of library that does not have problems you trying to work around.
If you want to fix your load from bytes you'd need to read all articles around https://blogs.msdn.microsoft.com/suzcook/2003/09/19/loadfile-vs-loadfrom/.

Why does the compiler when using an overload in another assembly sometimes require you to also reference a subassembly?

There are quite a few questions/answers about the compiler error mentionend below and how to resolve it, but the question here is asking about some insights why in this case this is required.
Why does a project A which uses an overload of a method of another referenced project B, which uses an object of project C in one of it's overloaded signatures require, that you reference project C from project A, even if you never use the object from project C?
I guess it must have to do with the resolving of which overload to use, but I'd like to understand the concept behind.
Here's an example:
Put each of the classes in an own assembly.
//Put into Assembly C
public class C {}
//Put into assembly B, reference C
public class B
{
public static void Test(string param) //Simple method with one string parameter
{
}
public static void Test(C param) //Overload which uses type of assembly C
{
}
}
//Call placed in method of assembly A which uses and references only assembly B, but not C
B.Test("TestString"); // fails to compile, CS0012
CS0012 The type 'C' is defined in an assembly that is not referenced.
You must add a reference to assembly 'C, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null'.
You can get interesting results when playing around with the overloads of assembly B, because not every combination does produce the error:
public static void Test(){}
public static void Test(C param){}
B.Test(); //Call from assembly A compiles
Another example:
public static void Test(string param){}
public static void Test(C param, int param2){}
B.Test(""); //Call from assembly A compiles
Yet another example:
public static void Test(string param, string param2){}
public static void Test(C param, int param2){}
B.Test("",""); //Fails, CS0012
So this propably has to do how the overload resolution is done. However, I don't understand why the compiler can't just work it's way up the dependency tree and requires me to do a direct reference? Wouldn't the overload resolution have to be done in assembly B anyways?

AssemblyResolve not fired for dependencies

I'm struggling with AssenblyResolve event for a while now. I've searched stackoverflow and did other googling and tried all that I think was relevant. Here are the links being the closer to my problem (in my opinion) :
AssemblyResolve is not invoked and FileNotFoundException is thrown during serialization
Where to handle AssemblyResolve event in a class library?
I have a Bootstrapper class with to static method (I will remove the thread safe code that we have, just for the sake of clarity :
public static void Initialize()
{
AppDomain.CurrentDomain.AssemblyResolve += CustomResolve;
}
private static Assembly CustomResolve(object sender, ResolveEventArgs args)
{
// There is a lot code here but basicall what it does.
// Is determining which architecture the computer is running on and
// extract the correct embedded dll (x86 or x64). The code was based
// on milang on GitHub (https://github.com/milang/P4.net). And it's the same
// purpose we want to be able to load the x86 or x64 version of the perforce dll
// but this time with the officially Perforce supported p4api.net.
// Once the dll is extracted we assign it to the boostrapper
Bootstrapper._p4dnAssembly = Assembly.LoadFile(targetFileName);
// Make sure we can satisfy the requested reference with the embedded assembly (now extracted).
AssemblyName reference = new AssemblyName(args.Name);
if (AssemblyName.ReferenceMatchesDefinition(reference, Bootstrapper._p4dnAssembly.GetName()))
{
return Bootstrapper._p4dnAssembly;
}
}
I was able to make the code work if the I have simple class with a main method and static constructor. The static constructor is simply calling the Boostrapper.Initialize() method.
After that, I could use my library and it was working as expected :
public static class Test
{
static Test()
{
Bootstrapper.Initialize();
}
public static void Main()
{
// Using the library here is working fine. The AssemblyResolve event was
// fired (confirmed by a breakpoint in Visual Studio)
}
}
The problem I have is if there is at least one layer of dependency. Basically the code stays the same but this time my the code of the library is inside another library :
public static class Test
{
static Test()
{
Bootstrapper.Initialize();
}
public static void Main()
{
Class1 myClass = new Class1();
// The following line is using the code of the extracted library, but
// The AssemblyResolve event is not fired (or fired before I register the
// callback) and therefore the library is not found : result
// BadImageFormatException() error could not load libary because one
myClass.Connect();
}
}
Sounds like #2 of the links I've previously stated explain what I'm seeing but it does not work. Visual Studio break point on the AssemblyResove callback is never being hit.
Any idea of what's going on?
Francis
I know it's been a while since this question was asked and answered, but I wanted to add my take on the issue anyway (since I just wasted a few hours over this, maybe thanks to this someone else wouldn't have to)
The problem is basically the fact, that the application is trying to resolve all assemblies needed to execute the method at the beginning of that method:
static void main(string[] args)
{
// <-- here the app tries to resolve MyAssembly
// and as MyAssembly.Class1 is not found, the app crashes
// this next line is never called:
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ResolveAssembly);
// class contained in an assemnly that we need to resolve
MyAssembly.Class1 myClass = new MyAssembly.Class1();
}
That's why the above will crash: the ResolveAssembly event handler will never be called because it was never hooked up.
And that's also why the below solution works (as posted by the OP):
static void main(string[] args)
{
Initialize();
RealMain();
}
static void Initialize()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ResolveAssembly);
}
static void RealMain()
{
// <-- here the app tries to resolve MyAssembly
// class contained in an assemnly that we need to resolve
MyAssembly.Class1 myClass = new MyAssembly.Class1();
// and everything is OK
}
Someone did answer but the answer has been deleted. So I can't mark it as answered.
Basically the fact the code needs not to be outside the "main" method is working.
Starting fresh from a new project, solve the issue so I guess I had some problems with the dll (probably x86 dll in x64 folder or vice-versa)
static void main(string[] args)
{
Boostrapper.Initialize();
RealMain();
}
static void RealMain()
{
Class1 myClass = new Class1();
myClass.Connect();
}

Why am I getting this exception when emitting classes that reference each other via value-type generics?

This code snippet is a simplified extract of my class-generation code, which creates two classes that reference each other as arguments in a generic type:
namespace Sandbox
{
using System;
using System.Reflection;
using System.Reflection.Emit;
internal class Program
{
private static void Main(string[] args)
{
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Run);
var module = assembly.DefineDynamicModule("Test");
var typeOne = module.DefineType("TypeOne", TypeAttributes.Public);
var typeTwo = module.DefineType("TypeTwo", TypeAttributes.Public);
typeOne.DefineField("Two", typeof(TestGeneric<>).MakeGenericType(typeTwo), FieldAttributes.Public);
typeTwo.DefineField("One", typeof(TestGeneric<>).MakeGenericType(typeOne), FieldAttributes.Public);
typeOne.CreateType();
typeTwo.CreateType();
Console.WriteLine("Done");
Console.ReadLine();
}
}
public struct TestGeneric<T>
{
}
}
Which should produce MSIL equivalent to the following:
public class TypeOne
{
public Program.TestGeneric<TypeTwo> Two;
}
public class TypeTwo
{
public Program.TestGeneric<TypeOne> One;
}
But instead throws this exception on the line typeOne.CreateType():
System.TypeLoadException was unhandled
Message=Could not load type 'TypeTwo' from assembly 'Test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
Source=mscorlib
TypeName=TypeTwo
StackTrace:
at System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, Int32 tk, ObjectHandleOnStack type)
at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
at System.Reflection.Emit.TypeBuilder.CreateType()
at Sandbox.Program.Main(String[] args) in C:\Users\aca1\Code\Sandbox\Program.cs:line 20
Interesting things to note:
The circular reference isn't required to cause the exception; if I don't define field One on TypeTwo, creating TypeOne before TypeTwo still fails, but creating TypeTwo before TypeOne succeeds. Therefore, the exception is specifically caused by using a type that has not yet been created as an argument in a generic field type; however, because I need to use a circular reference, I cannot avoid this situation by creating the types in a specific order.
Yes, I do need to use a circular reference.
Removing the wrapper TestGeneric<> type and declaring the fields as TypeOne & TypeTwo directly does not produce this error; thus I can use dynamic types that have been defined but not created.
Changing TestGeneric<> from a struct to a class does not produce this error; so this pattern does work with most generics, just not generic value types.
I can't change the declaration of TestGeneric<> in my case as it is declared in another assembly - specifically, System.Data.Linq.EntityRef<> declared in System.Data.Linq.dll.
My circular reference is caused by representing two tables with foreign key references to each other; hence the need for that specific generic type and this specific pattern.
Changing the circular reference to a self-reference edit succeeds. This failed originally because I had TestGeneric<> as a nested type in Program, so it inherited the internal visibility. I've fixed this now in the code sample above, and it does in fact work.
Compiling the generated code manually (as C# code) also works, so it's not an obscure compiler issue.
Any ideas on a) why this occuring, b) how I can fix this and/or c) how I can work around it?
Thanks.
I do not know exactly why this is occurring. I have a good guess.
As you have observed, creating a generic class is treated differently than creating a generic struct. When you create the type 'TypeOne' the emitter needs to create the generic type 'TestGeneric' and for some reason the proper Type is needed rather than the TypeBuilder. Perhaps this occurs when trying to determine the size of the new generic struct? I'm not sure. Maybe the TypeBuilder can't figure out its size so the created 'TypeTwo' Type is needed.
When TypeTwo cannot be found (because it only exists as a TypeBuilder) the AppDomain's TypeResolve event will be triggered. This gives you a chance to fix the problem. While handling the TypeResolve event you can create the type 'TypeTwo' and solve the problem.
Here is a rough implementation:
namespace Sandbox
{
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
internal class Program
{
private static void Main(string[] args)
{
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Run);
var module = assembly.DefineDynamicModule("Test");
var typeOne = module.DefineType("TypeOne", TypeAttributes.Public);
var typeTwo = module.DefineType("TypeTwo", TypeAttributes.Public);
typeOne.DefineField("Two", typeof(TestGeneric<>).MakeGenericType(typeTwo), FieldAttributes.Public);
typeTwo.DefineField("One", typeof(TestGeneric<>).MakeGenericType(typeOne), FieldAttributes.Public);
TypeConflictResolver resolver = new TypeConflictResolver();
resolver.AddTypeBuilder(typeTwo);
resolver.Bind(AppDomain.CurrentDomain);
typeOne.CreateType();
typeTwo.CreateType();
resolver.Release();
Console.WriteLine("Done");
Console.ReadLine();
}
}
public struct TestGeneric<T>
{
}
internal class TypeConflictResolver
{
private AppDomain _domain;
private Dictionary<string, TypeBuilder> _builders = new Dictionary<string, TypeBuilder>();
public void Bind(AppDomain domain)
{
domain.TypeResolve += Domain_TypeResolve;
}
public void Release()
{
if (_domain != null)
{
_domain.TypeResolve -= Domain_TypeResolve;
_domain = null;
}
}
public void AddTypeBuilder(TypeBuilder builder)
{
_builders.Add(builder.Name, builder);
}
Assembly Domain_TypeResolve(object sender, ResolveEventArgs args)
{
if (_builders.ContainsKey(args.Name))
{
return _builders[args.Name].CreateType().Assembly;
}
else
{
return null;
}
}
}
}

CurrentDomain.AssemblyResolve does not fire when assembly is used as a subclass

I am trying to use the CurrentDomain.AssemblyResolve event to load a DLL that is marked as an Embedded Resource. My problem, specifically, comes from the fact that I am trying to use the assembly as a subclass, like so:
#define BROKEN
using System;
using System.Reflection;
using TestCompanyInc;
namespace TestConsole
{
#if BROKEN
// This is how I NEED to use it
class Program : SubClass
#else
// This is only here as a test to make sure I wired
// CurrentDomain.AssemblyResolve correctly
class Program
#endif
{
static int Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) =>
{
string resourceName = Assembly.GetExecutingAssembly()
.GetName().Name
+ "." + new AssemblyName(eventArgs.Name).Name + ".dll";
Console.WriteLine("About to lookup {0}", resourceName);
using (var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName))
{
byte[] assemblyData = new byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
Program p = new Program(args);
return p.Run();
}
public Program(string[] args)
{
}
public int Run()
{
#if BROKEN
// This is how I NEED to use it
Console.WriteLine(TestProperty);
#else
// This is only here as a test to make sure I wired
// CurrentDomain.AssemblyResolve correctly
SubClass sc = new SubClass();
Console.WriteLine(sc.TestProperty);
#endif
Console.ReadKey();
return 0;
}
}
}
The test class SubClass is defined as:
namespace TestCompanyInc
{
public class SubClass
{
public SubClass()
{
TestProperty = "Init'd";
}
public string TestProperty { get; set; }
}
}
If the first line #define BROKEN is left uncommented, then the CurrentDomain.AssemblyResolve event will never fire and System.IO.FileNotFoundException is thrown and I am told that SubClass can not be found. If the first line is removed or commented out, then it will fire the event (but I can't use it this way).
I have also tried moving Main into its own class instead of having the same class create an instance of itself, but I get the exact same exception.
So, how do I get this event wired up correctly so it will load this assembly under these conditions?
Compiled in VS 2010 .NET 4, if that makes a difference to anyone. Also, for anyone trying to recreate this. SubClass is in its own project. Add SubClass as a Reference to TestConsole and mark it as Copy Local = False. I have read, somewhere, that this can not be a Project Reference, but a direct reference to the DLL. Then, add the DLL file to the TestConsole project and mark it as an Embedded Resource, not the default of Content.
Think about load-order... In order to JIT and invoke Main, it must understand Program. It can't understand Program without loading the base-class, which needs special handling. The event doesn't fire because it hasn't registered yet (because Main hasn't started).
That cannot work. The only way you can do this is to have an entry-point that doesn't depend on anything else. Note that JIT is done before the method starts, so the Main also can't involve anything that isn't known. For example, you might do:
class Loader {
static void Main()
{
// not shown: register assemy-load here
MainCore();
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void MainCore()
{ // your class as shown is Program
Program.Init();
}
}
Note we need 2 methods above since it can't JIT Main unless it can fully resolve Program. With the above, the event should fire just before MainCore() is invoked (I.e. During JIT for MainCore).

Categories

Resources