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();
}
Related
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.
we have one console application in which we have another class library that contains all the business functions in which we are using in main method of program file into that we are getting errors but that is not able to handle.
I find below code to add in program file to handle exception and create handler MyExceptionHandler.
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler);
In my project this only works when I have exception in Main method of program file, but when I have exception from Method of business function class it's not handling it.
Please suggest a better way to handle global exception.
.NET Global exception handler in console application
In this question they have different question then this as i already mention i already tried that solution. I am able to call it when it gives error in same program file method but when there is exceptions from another class library then its simply get back to main parent method.
I tried experiment below which I staged as you explained and everything is working.
....
// in ClassLibrary1 project
using System;
namespace ClassLibrary1
{
public class Class1
{
public void Method()
{
throw new Exception("Unhandled exception");
}
}
}
....
// in ConsoleApplication1 project
// ClassLibrary1 must be referenced
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler);
ClassLibrary1.Class1 class1 = new ClassLibrary1.Class1();
class1.Method();
}
static void MyExceptionHandler(object sender, UnhandledExceptionEventArgs e)
{// Break point here is hitting
// ... Processing exception ...
}
}
}
See if I did exactly as what you meant.
Why don't you just write a try-catch statement surrounding your logic in the main() method?
i.e.:
public void main(string[] args){
try{
// your logic that throws exceptions here (even calls to other dll's)
catch(Exception e){
// your exception handling logic here
}
}
Yet I may not understand your question completely as this is pretty basic stuff.
I have a need to embed referenced assemblies as resources in my own library. For this I have created a little sample solution with 3 projects in it.
The first is called First and has no dependencies. The second is called Second and is dependent on First. The third is OutProj and has a reference to Second.
I have found this article about the PreApplicationStartMethodAttribute. I have added
[assembly: PreApplicationStartMethod(typeof(SecondNs.Startup), "Start")]
to my test project's AssemblyInfo class (first line after includes). Next I have defined the class and method as such:
class Startup
{
public static void Start()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
}
static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
{
var name = args.Name.Substring(0, args.Name.IndexOf(','));
byte[] block = null;
switch (name)
{
case "First":
block = Properties.Resources.First;
break;
default:
break;
}
Assembly a2 = Assembly.Load(block);
return a2;
}
}
Both Second and OutProj have this class defined, with a difference in the switch case (the original code didn't do the trick so I modified it).
My main issue is that the Start method doesn't get called. When I add the start method code to my Main method it does indeed get called, but I don't have a Main in my class library. Is this the right approach or is there a better way to do this?
So here's a sample singleton:
public class Singleton
{
private static Singleton _instance = new Singleton();
private Singleton()
{
//do stuff
}
public static Singleton Get()
{
return _instance;
}
}
I'm trying to run multiple tests on this singleton class, and the first one always works, naturally. Basically, I'm able to see that when I create a new Singleton() the constructor is called. Or, when I call Singleton.Get() the constructor is called. The tests work fine individually, but then the static field has been set, and even if I manually set it to null, it still won't reset itself for the next test. This is a problem for me as automated testing is important here. So how can I get it to reset itself?
So far, I researched AppDomain and found that I could put each test into its own assembly and run it manually. But of course, VS already uses a unique AppDomain for each assembly which would allow for that to happen automatically, but that's a LOT of test assemblies and seems a bit silly. I'm looking for an alternative to that.
Note: I don't want advice about code quality. This is code I'm testing, not that I've written. I will not change the code until I've tested it first. I researched this thoroughly and did not find a question about this that was not answered with "You shouldn't use singletons". I am not interested in code advice. This is StackOverflow, not CodeReview.
Additional Information Requested
I am running tests currently using Visual Studio's Built-In Testing framework. I would prefer that this still worked when it is moved to MSBuild. That doesn't rule out manually triggering an external application for the tests, but it does make it harder to do.
You're misunderstanding AppDomains.
You can simply create a new AppDomain for each test, load all of the test assemblies into it, and invoke only one test method in each domain.
It would probably be rather slow, though.
You can design your Singleton class like this:
public class Singleton
{
private static Singleton _instance;
private static object _instanceLock = new object();
private Singleton()
{
//do stuff
}
public static Singleton Get()
{
if (_instance == null)
{
lock(_instanceLock)
{
if (_instance == null)
{
_instance = new Singleton();
}
}
}
return _instance;
}
public static void Clear()
{
if (_instance != null)
{
lock(_instanceLock)
{
if (_instance != null)
{
_instance = null;
}
}
}
}
}
Then you'd have to call Singleton.Clear() before you begin each test, like this:
[TestInitialize]
public void Initialize()
{
Singleton.Clear();
}
Write a console program that has a command-line argument to determine which of those singleton tests to run. Then call that multiple time from a batch file (or bash or powershell, whichever you prefer). It's extra work but it will let you test this code in a fresh new environment every time. Or you could try to figure out whether there's some option in your current tool to do that.
Perhaps something like that:
static int Main(string[] args) {
try {
int testcase = (Int32.Parse(args[0]));
RunTest(testcase);
} catch (Exception x) {
Console.WriteLine("test failed: "+x.Message);
return 1;
}
Console.WriteLine("test passed.");
return 0;
}
After numerous bits of advice from #redtuna #drch and #SLaks and lots of googling we have determined a way to do this.
Step 1: Your test class needs to inherit from MarshalByRefObject
public class UnitTest1 : MarshalByRefObject
Step 2: This next piece is a custom method to run each test in it's own AppDomain.
private void RunTestInCustomDomain(string methodName)
{
// selecting the dll from the debug directory using relative directories
var testDll = #"..\..\..\UnitTests\bin\Debug\UnitTests.dll";
// first verify the dll exists
Assert.IsTrue(File.Exists(testDll));
var assemblyName = AssemblyName.GetAssemblyName(testDll).FullName;
var domain = AppDomain.CreateDomain(methodName, null, new AppDomainSetup()
{
// This is important, you need the debug directory as your application base
ApplicationBase = Path.GetDirectoryName(testDll)
});
// create an instance of your test class
var tests = domain.CreateInstanceAndUnwrap(assemblyName, typeof(UnitTest1).FullName) as UnitTest1;
var type = tests.GetType();
var method = type.GetMethod(methodName);
// invoke the method inside custom AppDomain
method.Invoke(tests, new object[]{});
// Unload the Domain
AppDomain.Unload(domain);
}
Step 3: The next trick is that your Test Method is calling this custom method, so your tests are written into public methods without the [TestMethod] attribute.
[TestMethod]
[DeploymentItem("UnitTests.dll")]
public void TestMethod1()
{
RunTestInCustomDomain("actual_TestMethod1");
}
public void actual_TestMethod1()
{
// Assert Stuff
}
For Completeness: If you need to run initialization or cleanup for each test, they need to be called manually because the TestMethod is running in a different AppDomain from the actual_TestMethod
public void actual_TestMethod1()
{
// Assert Stuff
TestCleanup();
}
Edit: I should note that because these methods are being run under a separate AppDomain, Code Coverage doesn't work :(. If anyone finds a way to get that functionality in addition to this feature, please let me know.
Just an idea:
Setting it to null just sets your variable to null instead of what it's pointing at, of course. But what if you could get the Singleton itself... Well, it seems that that can be done using Expressions. See Getting the object out of a MemberExpression?
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).