Catching missing DLL in XamlParseException - c#

I have quite an unusual problem where if there is a missing DLL on the client machine, the application will freeze and display the standard "The application is not responding". However, as I know what the issue is, I'd like to find a way to catch this exception (Missing DLL) and display the message in a dialog displaying meaningful information to help identify which DLL is missing. This will allow the application to have a more graceful death.
Upon debugging on the client machine, I receive the error:
A first chance exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll
Additional information: Could not load file or assembly 'Some.DLL' or one of its dependencies. The system cannot find the file specified.
In release however, the application crashes and is not responding.
Looking at the documentation for this error, a XamlParseException usually occurs inside the InitializeComponent(); method:
For pages of an application, when the XamlParseException is thrown, it is usually in the context of the InitializeComponent call made by your page class, which is the entry point for the WPF application model's usage of the WPF XAML parser at the per-page level. Therefore another possible handling strategy is to place try/catch blocks in InitializeComponent. However, this technique does not integrate well with templates, visual design surfaces and other generated sources that hook up InitializeComponent.
So, I can do something like this:
public MyView()
{
try
{
InitializeComponent();
}
catch (XamlParseException ex)
{
//Do something useful with the error.
}
}
This is certainly possible, however it would require using this code in practically all controls, which is obviously ridiculous. Not to mention that it doesn't really solve the issue of a missing DLL.
So, my questions are:
Is it possible to trap a missing DLL and display a message containing the name of said DLL?
Is there a more elegant way of catching a XamlParseException?
Thanks.

Yes, it is certainly possible.
To do this, you will need to override what happens when the application first starts up.
Open your Application.xaml.vb, and add the following code:
protected override void OnStartup(StartupEventArgs e)
{
// add an event handler for the UnhandledException event
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(HandleException);
// start up the application
base.OnStartup(e);
}
// what to do when the exception is thrown
void HandleException(object sender, UnhandledExceptionEventArgs e)
{
// do something with the exception
MessageBox.Show(e.ExceptionObject.ToString());
}
The output from the e.ExceptionObject.ToString() contains the problem. In the case you describe, there will probably be nested exceptions, the inner one stating : System.IO.FileNotFoundException: Could not load file or assembly '{missing DLL name here}' or one of its dependencies. The system cannot find the file specified. at {Project}.{where the error was thrown}

Related

See what method is currently being used from a DLL

I know that I can open a DLL file with an assembly browser, such as ILSpy, to see the classes and methods that it contains. But if a process is currently using a DLL, is it possible to know what method it is currently using? And any other details, such as the exact line that it is on, and if it threw an exception?
This question isn't language specific, but I'm most interested in doing this in C#. And the DLLs are compiled in the .NET framework.
My goal is to build a logger that shows what part of my code a process is using, and if it threw an exception, which function it came from.
The closest I know how to get to this is to check the callstack of a process. It is easy to do this using ProcessExplorer (get it here: https://technet.microsoft.com/en-gb/sysinternals/bb896653.aspx)
Then:
Open Process Explorer, select the process you need more information
about, then right click > Properties...
Select the 'Threads' tab. This will open up the list of all threads for this process.
Select the thread you are interested in then click on 'Stack' This will reveal the list of loaded DLLs and the method called
You should get something like this:
Note that the above would work if PE can resolve symbols. This page provides an example on how to enable symbol resolution in Process Explorer : http://windowsexplored.com/2012/01/31/resolve-symbols-in-process-explorer-monitor-without-installing-the-debugging-tools/
1.A simple approach will be to add into Main() function
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
and the handler will be something like
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
string errorMessage = e.ExceptionObject.ToString();
Logger.Error(e.ExceptionObject.ToString());
Current.Shutdown(1);
}
2.you can use ProcDump with the flag "-e" to catch unhandled exceptions.
for example myApp.exe:
Procdump -ma -e -w myApp.exe C:\temp\fe.dmp
and then you will need to load some stuff for winDB
1. load the dump file into WinDBG
2. .loadby sos clr in winDBG
3. !printexception
0:005> !printexception
Exception object: 0000000002becc68
Exception type: System.NullReferenceException
Message: Object reference not set to an instance of an object.
InnerException: <none>
StackTrace (generated):
SP IP Function
000000001B94F190 000007FF7E551B74 myApp!myApp.MainForm+...
000000001B94F220 000007F8010FFD85 mscorlib_ni!System.Threading...
000000001B94F380 000007F8010FFAE9 mscorlib_ni!System.Threading...
000000001B94F3B0 000007F8010AC31F mscorlib_ni!System.Threading...
000000001B94F400 000007F8010AC92A mscorlib_ni!System.Threading... ...
you might need SOSEX extension as well

When does Silverlight show "Debugging resource strings are unavailable." message?

I have had a few reports of a message box showing up on application launch with the following contents:
[Arg_NullReferenceException]
Arguments:
Debugging resource strings are unavailable. Often the key and arguments provide
sufficient information to diagnose the problem. See http://go.microsoft...
I understand the link provided gives me the exception detail, and I obviously have a null ref somewhere. I haven't been able to reproduce this, so I am trying to find where this message is being thrown and hopefully add some error handling.
Is this specific message box something baked into Silverlight, or is it following whatever exception handling is in place when such an exception occurs? In the app constructor, I have
this.UnhandledException += this.Application_UnhandledException;
which is:
private void Application_UnhandledException(object sender,
ApplicationUnhandledExceptionEventArgs e)
{
MessageBox.Show(e.ExceptionObject.Message + "\n" + e.ExceptionObject.StackTrace);
}
So it looks like this message box is not coming from the Application_UnhandledException or it would have a message, newline, then a stack trace. So now my two options for how this message box is being generated are: 1) Silverlight is doing it in the background, or 2) this is coming from an existing catch block, although I have found none that would display in this way.
I'm doing offline caching of XAPs in Isolated Storage using OfflineCatalog, which involves some asynchronous WebClient downloads and fall-backs to Isolated Storage when requests fail. It makes sense that a null ref might be happening somewhere in this process.
To summarize, I'm wanting to add some exception handling for this Null Reference, but cannot reproduce it locally, and cannot find where it may be coming from. If this is coming from an unhandled exception, why does it not display the message and stack trace as specified?
The error message occurs if the machine does not have Silverlight SDK installed normally.
To debug similar browser side exceptions, it is common practice to use Visual Studio. If you cannot use VS, simply use WinDbg to attach to the browser process.

Unhandled exception swallowed (except in debugger)

I'm maintaining a legacy C# Winform application, using .NET 4.0 framework. The application works fine, but occasionally due to bugs in the application, the application will fail to work properly when the the application creates invalid data in the database.
At certain points, we bind the (invalid/corrupt) data to a datagrid, which causes numerous errors when it attempts to map a null column to a datagrid column.
An exception of type 'System.InvalidCastException' occurred in mscorlib.dll but was not handled in user code
Additional information: Object cannot be cast from DBNull to other types.
As well as
An exception of type 'System.Reflection.TargetInvocationException' occurred in System.Windows.Forms.dll but was not handled in user code
The errors cause a nice popup to show when run under the Visual Studio debugger detailing the error as well as allowing me to see the line where the error occurred.
In this particular case, I know what the issue is, so I can easily correct it. However, this class of error occurs too-often in other parts of the application, so it's not always obvious what is happening, and my users don't always provide good error reports. To try and combat this, I'd like to add logging to the application (using log4net), which works in our situation as each user has their own copy of the application so I can obtain per-user logs after the fact.
Using hints from stackoverflow as well as various other sources, I found a lot of good information on setting up handlers for these unhandled exceptions. Unfortunately, my handlers are not being called for the majority of the 'unhandled' exceptions.
The mostly relevant parts of the application are below:
static class Program {
private static readonly ILog log = LogManager.GetLogger("Main");
static void Main() {
// Add some error handlers which log error data to the logfile
//
// For UI events (set the unhandled exception mode to force all Windows Forms
// errors to go through our handler)
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += new ThreadExceptionEventHandler(delegate(object s, ThreadExceptionEventArgs e) {
ExceptionLogger(e.Exception);
});
// Non-UI thread exceptions
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(delegate(object sender, UnhandledExceptionEventArgs e) {
ExceptionLogger(e.ExceptionObject as Exception);
});
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
log.Debug("Starting Application");
Application.Run(mainForm = new MainForm());
}
private static void ExceptionLogger(Exception e) {
log.Error("Unhandled Error", e);
string errorMsg = "An application error occurred. Please contact the administrator with the following information:\n\n";
errorMsg = errorMsg + e.Message + "\n\nStack Trace:\n" + e.StackTrace;
if (MessageBox.Show(errorMsg, "TLMS Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop) == DialogResult.Abort)
Application.Exit();
}
The Exception handler seems to work if the errors occur directly in my own code, but the handler is not called if/when the errors occur directly in the .NET libraries, and I want the handler called for all Unhandled exceptions, including those outside of code I've written.
Being able to use the debugger to track down the errors is invaluable if I can recreate the exact users steps within the debugger after the fact. However, at no point is ExceptionLogger being called, either running standalone or inside the debugger, and there is no visual indication that any error occurred. Because the exceptions are being suppressed, the users sometimes don't realize until much too late that everything they've done is completely screwed up and the data is even more corrupt.
The application platform is being built and run on x86 (apparently exceptions can be lost if run on x64), and the application has been tested on both 64-bit and 32-bit platforms with no change in behavior.
So you only see "but was not handled" when the app runs in the debugger. When it runs outside the debugger exceptions are suppressed. If I've got this correct then I still think the app handles the exceptions, because the debugger changes app behaviour sometimes.
I confirmed that InvalidCastException is one of a group of exceptions that .NET 4+ handles differently if the exception context is unmanaged code. An app can override this special handling (see All about Corrupted State Exceptions in .NET 4), but the debugger may ignore the override. There are lots of web resources on this, see also one in MSDN Magazine.
EDIT: If your app users have .NET 3.5 or below installed then the app need not apply the override described in the resources above.

In a C# class library how can I detect when the DLL is about to be unloaded?

I need to write a static List to a text file when a DLL is unloaded. I've tried doing this on AppDomain.CurrentDomain.DomainUnload but it crashes with the error "DefaultDataCollection failed: 0x8007001f".
What is the best way to do this?
Thanks,
Joe
0x8007001f
That's a WIN32 error (the 7 in the middle is FACILITY_WIN32): ERROR_GEN_FAILURE:
A device attached to the system is not functioning.
So you need to look at the exception type and stack trace to get more details of what is failing.
AppDomain.CurrentDomain.DomainUnload
but remember the documentation has the caveat:
This event is never raised in the default application domain.

C#: How to embed DLL into resourcefile (no dll copy in program directory)

I have a C# application (project A) that requires X.dll. I have added the project that produces X.dll to A as a reference in visual studio. I have also added the release build of X.dll to a resource file in A as a binary. I have told project A not to copy X.dll to the output directory.
Now I want A.exe to load, say "hey I can't find this file", then look in the resource file and use Assembly.Load(byte[]) get X.dll back. I have the code that re-magicifies the DLL back, however this code never get called.
Currently I have a bone simple project, just trying to get it to work. It compile OK. When I run it, I get a FileNotFoundException on X.dll.
I have:
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
But the breakpoint in *CurrentDomain_AssemblyResolve* never gets hit. I get a FileNotFoundException immediately. Surely there is something I a missing?
This question seems to be very similar to what you are trying to achieve, and it worked for the asker.
Merge .dll into C# Assembly?
Are you doing something differently? Specifically, if you're targetting an older version of the .NET Framework, maybe that's a hint for understanding why your application is behaving differently.
Another direction, use a tool such as Fusion Log Viewer to analyze what was going on when you tried to load the assembly. This may give some more hints. If you manage to get log information, posting it in the question may help someone figure it out.
EDIT: Another explanation, following your comment.
Well, now I think I know what the problem is.
In your Main method, you are refering to the type in the other dll. But you are doing it in static code, i.e. you use the type explicitly in the code (as opposed to loading it dynamically by its name).
Why is this a problem? The CLR tries to load your assembly in order to JIT Main itself.
Your FileNotFoundException was thrown while Main was being compiled. Main didn't even start running, and therefore your event handler wasn't registered.
A simple way to check if I'm right is to change the code to something like this:
static public void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += MyEventHandler;
MyMain();
}
// The CLR will actually try to load your assembly before even starting the execution
// of this method. It needs the assembly in order to JIT the method because it has to
// know the Thing type.
static public void MyMain()
{
using(var thing = new Thing())
{
// ...
}
}
The important difference is that Main has no dependency on another assembly, so there will be no problem to JIT and run it.
By the time MyMain is being JIT'ed, your event handler is already in place so you can manually load the assembly.
By the way, to avoid another possible similar pitfall, make sure that the class in which Main is defined doesn't have any field with a type from the other assembly, because in this case also, the CLR will try loading the assembly before Main starts, in order to compile it.

Categories

Resources