How to capture the abscence of a library in Visual Studio? - c#

I have developed a custom library that I use in some projects.
Nowadays I'm implementing the error capture in my application. One of them considers the possibility that the machine where I try to execute my application doesn't have my libraries.
So what I made to check if the library was installed or not, was try to use it surrounded with a try-catch clause like this:
try
{
MyLibrary library = new MyLibrary();
}
catch (Exception e)
{
MessageBox.Show("Your library is not installed");
Close();
}
This code should show a message when the library is not found, and then close my application. But the message is never shown.
Any idea on how to check if my library is not located in my machine?

With your current try-catch you can not catch that kind of exception because there are not related to your code. The Runtime will try to load the assembly, if it cannot be found, the AssemblyResolve event is raised.
class Test
{
public static void Main()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += MyResolveEventHandler;
}
private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
Console.WriteLine("Try resolving: " + args.Name);
return null;
}
}

Related

How to fix NullReferenceException occurring only on some computers

I create a setup file of a winform app using VS 2017 installer. When I test this setup file on my PC, the login runs fine. So I run this setup file on other PCs.
However, when I login the app in these PCs, the app say "Object reference not set to an instance of an object", though I am sure that the username and password were correct in the db.
I have seen What is a NullReferenceException, and how do I fix it?, but I do not think it is the null exception, because the installed app did not throw above error in my PC. This error only happens when I install the app in other PCs.
I also try replacing the .exe and .config files in folder of the installed app in other PCs with the same files of the app in my PC (which work well), and the app runs ok. But then I restart those PCs, and try to login the app, the same error happens.
This is the code for login. I believe that I have checked for the null exception properly. Am I right?
private void btnLogin_Click(object sender, EventArgs e)
{
try
{
var info = UsersBiz.Login(txtUserName.Text.Trim(), txtPassWord.Text);
if (info != null && info.user.Id > 0)
{
Constants.USERINFO = info;
this.Hide();
var frm = new frmMain();
frm.Show();
if (ckbRemember.Checked)
{
ManagementInventory.Properties.Settings.Default.User = txtUserName.Text;
ManagementInventory.Properties.Settings.Default.Pass = txtPassWord.Text;
ManagementInventory.Properties.Settings.Default.Save();
}
}
else
{
MessageBox.Show("UserName or Password not correct!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The most easy way would be to use visual studio debugger on the computer where the program runs. If there is no visual studio on that computer, consider using remote debugging. See how to start debugging on a remote computer
If for security reasons remote debugging is out of the question, consider to log the exception, especially the stack trace. If you know where it occurs, simply surround it with a try-catch
try
{
// Here are the statements that cause your ArgumentNullException
}
catch (ArgumentNullException exc)
{
// log the exception
}
If your program has no logging facility, consider adding something like NLOG. Another possibility is to append it to a text file.
void WriteExceptionToTextFile(Exception exc, string fileName)
{
using (var writer = File.AppendText(fileName))
{
writer.WriteLine("Exception {0}", exc.GetType());
write.WriteLine("Stack trace" + exc.StackTrace);
... // etc
}
}
If you don't know where the exception occurs, you can't try-catch it. In that case consider to catch the unhandled exception and log it:
See: catching unhandled exception
In your forms program is a file program.cs which contains the main:
public static void Main()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += OnUnhandledException;
...
}
static void OnUnhandledException(object sender, UnhandledExceptionEventArgs args)
{
Exception undhandledException = (Exception) args.ExceptionObject;
// TODO log the unhandled exception
}

Gracefully handling corrupted state exceptions

Related to this question, I would like to force CLR to let my .NET 4.5.2 app catch Corrupted State Exceptions, for the sole purpose of logging them and then terminating the application. What's the correct way to do this, if I have catch (Exception ex) at several places around the app?
So, after I specify the <legacyCorruptedStateExceptionsPolicy> attribute, if I understood correctly, all the catch (Exception ex) handlers will catch exceptions like AccessViolationException and happily continue.
Yeah, I know catch (Exception ex) is a Bad Idea™, but if CLR would at least put the correct stack trace into the Event Log, I would be more than happy to explain to the customer that his server app failing fast at 1AM and being offline for the night is a good thing. But unfortunately, CLR logs an unrelated exception into the Event Log and then closes the process so that I cannot find out what actually happened.
The question is, how to make this happen, process wide:
if the exception thrown is a Corrupted State Exception:
- write the message to the log file
- end the process
(Update)
In other words, this would probably work for most exceptions in a simple app:
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
static void Main() // main entry point
{
try
{
}
catch (Exception ex)
{
// this will catch CSEs
}
}
But, it won't work for:
Unhandled app domain exceptions (i.e. thrown on non-foreground threads)
Windows Service apps (which don't have an actual Main entry point)
So it seems like <legacyCorruptedStateExceptionsPolicy> is the only way to make this work, in which case I don't know how to fail after logging the CSE?
Instead of using <legacyCorruptedStateExceptionsPolicy> it would be better to use [HandleProcessCorruptedStateExceptions] (and [SecurityCritical]) as stated here:
https://msdn.microsoft.com/en-us/magazine/dd419661.aspx
Following that, your Main method should look something like this:
[HandleProcessCorruptedStateExceptions, SecurityCritical]
static void Main(string[] args)
{
try
{
...
}
catch (Exception ex)
{
// Log the CSE.
}
}
But be aware that this doesn't catch the more serious exceptions like StackOverflowException and ExecutionEngineException.
Also finally of involved try blocks will not be executed:
https://csharp.2000things.com/2013/08/30/920-a-finally-block-is-not-executed-when-a-corrupted-state-exception-occurs/
For other unhandled appdomain exceptions you can use :
AppDomain.CurrentDomain.UnhandledException
Application.Current.DispatcherUnhandledException
TaskScheduler.UnobservedTaskException
(Please do a search for the details when a specific handler is appropriate for your situation. TaskScheduler.UnobservedTaskException for example is a bit tricky.)
If you don't have access to the Main method, you can also mark your AppDomain exception handler to catch the CSE:
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
...
[HandleProcessCorruptedStateExceptions, SecurityCritical]
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// AccessViolationExceptions will get caught here but you cannot stop
// the termination of the process if e.IsTerminating is true.
}
The last line of defense could be an unmanaged UnhandledExceptionFilter like this:
[DllImport("kernel32"), SuppressUnmanagedCodeSecurity]
private static extern int SetUnhandledExceptionFilter(Callback cb);
// This has to be an own non generic delegate because generic delegates cannot be marshalled to unmanaged code.
private delegate uint Callback(IntPtr ptrToExceptionInfo);
And then somewhere at the beginning of your process:
SetUnhandledExceptionFilter(ptrToExceptionInfo =>
{
var errorCode = "0x" + Marshal.GetExceptionCode().ToString("x2");
...
return 1;
});
You can find more information about the possible return codes here:
https://msdn.microsoft.com/en-us/library/ms680634(VS.85).aspx
A "specialty" of the UnhandledExceptionFilter is that it isn't called if a debugger is attached. (At least not in my case of having a WPF app.) So be aware of that.
If you set all the appropriate ExceptionHandlers from above, you should be logging all exceptions that can be logged. For the more serious exceptions (like StackOverflowException and ExecutionEngineException) you have to find another way because the whole process is unusable after they happened. A possible way could perhaps be another process that watches the main process and logs any fatal errors.
Additional hints:
In the AppDomain.CurrentDomain.UnhandledException you can safely cast the e.ExceptionObject to Exception without having to worry - at least if you don't have any IL code that throws other objects than Exception: Why is UnhandledExceptionEventArgs.ExceptionObject an object and not an Exception?
If you want to suppress the Windows Error Reporting dialog, you can take a look here: How to terminate a program when it crashes? (which should just fail a unit test instead of getting stuck forever)
If you have a WPF application with multiple dispatchers you can also use a Dispatcher.UnhandledException for the other dispatchers.
Thanks to #haindl for pointing out that you can also decorate handler methods with the [HandleProcessCorruptedStateExceptions]1 attribute, so I made a little test app just to confirm if things really work as they are supposed to.
1 Note: Most answers state that I should also include the [SecurityCritical] attribute, although in the tests below omitting it didn't change the behavior (the [HandleProcessCorruptedStateExceptions] alone seemed to work just fine). However, I will leave both attributes below since I am presuming all these folks knew what they were saying. That's a school example of "Copied from StackOverflow" pattern in action.
The idea is, obviously, to remove the <legacyCorruptedStateExceptionsPolicy> setting from app.config, i.e. only allow our outermost (entry-level) handler(s) to catch the exception, log it, and then fail. Adding the setting will allow your app to continue, if you catch the exception in some inner handler, and this is not what you want: the idea is just to get the accurate exception info and then die miserably.
I used the following method to throw the exception:
static void DoSomeAccessViolation()
{
// if you have any questions about why this throws,
// the answer is "42", of course
var ptr = new IntPtr(42);
Marshal.StructureToPtr(42, ptr, true);
}
1. Catching exceptions from Main:
[SecurityCritical]
[HandleProcessCorruptedStateExceptions]
static void Main(string[] args)
{
try
{
DoSomeAccessViolation();
}
catch (Exception ex)
{
// this will catch all CSEs in the main thread
Log(ex);
}
}
2. Catching all exceptions, including background threads/tasks:
// no need to add attributes here
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += UnhandledException;
// throw on a background thread
var t = new Task(DoSomeAccessViolation);
t.Start();
t.Wait();
}
// but it's important that this method is marked
[SecurityCritical]
[HandleProcessCorruptedStateExceptions]
private static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// this will catch all unhandled exceptions, including CSEs
Log(e.ExceptionObject as Exception);
}
I would recommend using just the latter approach, and removing the [HandleProcessCorruptedStateExceptions] from all other places to make sure the exception doesn't get caught at the wrong place. I.e. if you have a try/catch block somewhere and an AccessViolationException is thrown, you want CLR to skip the catch block and propagate to the UnhandledException before ending the app.
Is party over? not so fast
Microsoft: "Use application domains to isolate tasks that might bring down a process."
The program below will protect your main application/thread from unrecoverable failures without risks associated with use of HandleProcessCorruptedStateExceptions and <legacyCorruptedStateExceptionsPolicy>
public class BoundaryLessExecHelper : MarshalByRefObject
{
public void DoSomething(MethodParams parms, Action action)
{
if (action != null)
action();
parms.BeenThere = true; // example of return value
}
}
public struct MethodParams
{
public bool BeenThere { get; set; }
}
class Program
{
static void InvokeCse()
{
IntPtr ptr = new IntPtr(123);
System.Runtime.InteropServices.Marshal.StructureToPtr(123, ptr, true);
}
// This is a plain code that will prove that CSE is thrown and not handled
// this method is not a solution. Solution is below
private static void ExecInThisDomain()
{
try
{
var o = new BoundaryLessExecHelper();
var p = new MethodParams() { BeenThere = false };
Console.WriteLine("Before call");
o.DoSomething(p, CausesAccessViolation);
Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); //never stops here
}
catch (Exception exc)
{
Console.WriteLine($"CSE: {exc.ToString()}");
}
Console.ReadLine();
}
// This is a solution for CSE not to break your app.
private static void ExecInAnotherDomain()
{
AppDomain dom = null;
try
{
dom = AppDomain.CreateDomain("newDomain");
var p = new MethodParams() { BeenThere = false };
var o = (BoundaryLessExecHelper)dom.CreateInstanceAndUnwrap(typeof(BoundaryLessExecHelper).Assembly.FullName, typeof(BoundaryLessExecHelper).FullName);
Console.WriteLine("Before call");
o.DoSomething(p, CausesAccessViolation);
Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); // never gets to here
}
catch (Exception exc)
{
Console.WriteLine($"CSE: {exc.ToString()}");
}
finally
{
AppDomain.Unload(dom);
}
Console.ReadLine();
}
static void Main(string[] args)
{
ExecInAnotherDomain(); // this will not break app
ExecInThisDomain(); // this will
}
}

AppDomain unhandled exceptions

There are plenty of topics covering the question. But nevertheless I have a problem.
I load the assembly into new AppDomain like this:
public void Run()
{
//There's the problem.
//As Panos Rontogiannis mentioned the thread is created in default AppDomain
new Thread(RunApp).Start();
}
private void RunApp()
try
{
AppDomain.CreateDomain("domain name").ExecuteAssembly("path to assembly");
}
catch (Exception _e)
{
MessageBox.Show("Unhandled Exception.\n" + _e);
}
}
In the Main method of the loaded assembly I subscribe my handler to the UnhandledException event:
AppDomain.CurrentDomain.UnhandledException += handleException;
The handler itself:
public static void handleException(object a_s, UnhandledExceptionEventArgs a_args)
{
var _e = (Exception)a_args.ExceptionObject;
//Static loger class method
Loger.WriteError(_e.GetType().ToString(), _e.Message, "default solution");
}
But wherever the exception is thrown in the loaded assembly the handler doesn't get involved. I only catch exception in the default AppDomain (first try{} catch{}).
Most probably, the reason you cannot handle the exception in the new AppDomain is that it is not thrown from a thread that was created in that AppDomain. From the documentation on AppDomain.UnhandledException it is not very straight-forward to see that. The interesting part is the following:
An exception is unhandled only if the entire stack for the thread has
been unwound without finding an applicable exception handler, so the
first place the event can be raised is in the application domain where
the thread originated.
Now if the thread that executes the code that throws, is created in your main AppDomain (like the main thread of a console app), then you should add a handler in the main AppDomain. Note though that if the type of the thrown exception is not loaded in the main AppDomain, the Assembly Loader of .NET will try to load it from your applications' base directory and probing paths. If these are not the same with the child AppDomain, then the assembly will not be resolved and an(other) exception will be thrown.
There are a variety of reasons that this might happen. The event documentation at http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx covers quite a bit of this complexity in detail If nothing there seems applicable, could you please post repro code?
My guess is the handler is not invoked as the exception is handled. i.e. By the upper try{}catch{}.
I didn't realy understand why the handler doesn't get invoked.
I ended up using FirstChanceException instead of UnhandledException in Main method of loaded assembly. Like this:
AppDomain.CurrentDomain.FirstChanceException +=
(obj, e) => Loger.WriteError(
e.Exception.ToString(),
e.Exception.Message,
"default solution"
);
This is a late reply, but this seems to work fine if you ask me (VS2012/.NET 4.5), exception handler needs to be registered before ExecuteAssembly is called of course: (I have a child process that causes an Access Violation by writing to a null ref (unsafe code) just to force a crash and it triggers the HandleException below:
public static void HandleException(object a_s, UnhandledExceptionEventArgs a_args)
{
var _e = (Exception)a_args.ExceptionObject;
Console.WriteLine(_e.GetType().ToString(), _e.Message, "default solution");
}
public void StarProcessWithinAppDomain(string fileName)
{
try
{
// New appdoamin / check exception isolation level
AppDomain sandBox = AppDomain.CreateDomain("sandBox");
try
{
AppDomain.CurrentDomain.UnhandledException += HandleException;
sandBox.ExecuteAssembly(fileName);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred (inner) within AppDomain, executing \"{0}\":" + "\n" + ex.Message, fileName);
}
finally
{
AppDomain.Unload(sandBox);
}
}
catch (Exception ex)
{
Console.WriteLine("An error occurred within AppDomain, executing \"{0}\":" + "\n" + ex.Message, fileName);
}
}
FirstChanceException fires.
Any catch blocks are executed.
If no catch block or throw in the block then UnhandledException fires
Your catch block ensures that UnhandledException doesn't fire.

FileNotFoundExceptions for System.Data.SQLite not catched

I use System.Data.SQLite in my project. When there is no System.Data.SQLite dll in output folder I can't catch FileNotFoundException (other exception catched fine). Here is the code exapmle:
private void button1_Click(object sender, RoutedEventArgs e)
{
try
{
SQLiteConnection conn = new SQLiteConnection();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
MessageBox doesn't showed. If I extract this code in separate function and wrap this function call in try catch than catching exception work fine and MessageBox showed:
private void DeclareConnection()
{
SQLiteConnection conn = new SQLiteConnection();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
try
{
DeclareConnection();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
What is the problem?
You will have to handle the AppDomain.AssemblyResolve event,
Subscribe to the AssemblyResolve event
AppDomain.CurrentDomain.AssemblyResolve += HandleAssemblyResolve;
here is some example code that handles the loading of x86 / x64 SQLite assemblies in c#
public static Assembly HandleAssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name.Contains("System.Data.SQLite"))
{
if (_assembliesResolved)
return null;
Assembly returnValue;
string executingAssemblyPath = Assembly.GetExecutingAssembly().Location;
executingAssemblyPath = Path.GetDirectoryName(executingAssemblyPath);
if (Environment.Is64BitProcess)
executingAssemblyPath = Path.Combine(executingAssemblyPath, #"lib-sqlite\x64\", "System.Data.SQLite.dll");
else //32 bit process
executingAssemblyPath = Path.Combine(executingAssemblyPath, #"lib-sqlite\x86\", "System.Data.SQLite.dll");
returnValue = Assembly.LoadFrom(executingAssemblyPath);
_assembliesResolved = true;
return returnValue;
}
return null;
}
You cannot catch exceptions generated by the fact that a refereced assembly was not found.
Only if you manually load the assembly with Reflection you could catch the exception.
To check if the sqlite assembly is there, do a File.Exists().
In the first case you cannot catch the exception because the jit throws the exception as soon as it hits the method. In the second case it jits your method and the exception is thrown by the time it tries to jit the DeclareConnection method.

The uncatchable exception, pt 2

Update: I've filed a bug report on Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/details/568271/debugger-halting-on-exception-thrown-inside-methodinfo-invoke#details
If you can reproduce this problem on your machine, please upvote the bug so it can be fixed!
Ok I've done some testing and I've reduced the problem to something very simple:
i. Create a method in a new class that throws an exception:
public class Class1 {
public void CallMe() {
string blah = null;
blah.ToLower();
}
}
ii. Create a MethodInfo that points to this method somewhere else:
Type class1 = typeof( Class1 );
Class1 obj = new Class1();
MethodInfo method = class1.GetMethod( "CallMe" );
iii. Wrap a call to Invoke() in a try/catch block:
try {
method.Invoke( obj, null ); // exception is not being caught!
} catch {
}
iv. Run the program without the debugger (works fine).
v. Now run the program with the debugger. The debugger will halt the program when the exception occurs, even though it's wrapped in a catch handler that tries to ignore it. (Even if you put a breakpoint in the catch block it will halt before it reaches it!)
In fact, the exception is happening when you run it without the debugger too. In a simple test project it's getting ignored at some other level, but if your app has any kind of global exception handling, it will get triggered there as well. [see comments]
This is causing me a real headache because it keeps triggering my app's crash-handler, not to mention the pain it is to attempt to debug.
I can reproduce this on my .NET 4 box, and you're right -- it only happens on .NET 4.0.
This smells very much like a bug to me, and should go on MS Connect. Major bummer if this is tripping your crash handler. Sounds like a non-pleasing way to work around this is to wrap the invoked method inside its own handler. :-(
One thing I can not reproduce, though, is tripping the crash handler. Here's my program:
namespace trash {
public class Class1 {
public void CallMe() {
string blah = null;
blah.ToLower();
}
}
class Program {
static void Main(string[] args) {
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
var class1 = typeof(Class1);
var method = class1.GetMethod("CallMe");
try {
var obj = new Class1();
method.Invoke(obj, null); // exception is not being caught!
}
catch (System.Reflection.TargetInvocationException) {
Console.Write("what you would expect");
}
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
Console.Write("it would be horrible if this got tripped but it doesn't!");
}
}
}
You can't catch all exceptions. There's a few assumptions in your example. You are, for instance, assuming the exception was raised on the calling thread. Catching unhandled exceptions on other threads depends on which runtimes you're using (console, winforms, WPF, ASP.Net, etc).
Additionally, calls to System.Environment.FailFast() do not generate any handlable condition - the process is effectively terminated with no chance for intervention.

Categories

Resources