WinForms exception interceptor - winforms

I'm using the ABP framework with WinForms and I need to identify the best way to intercept an exception and log this information.
My WinForms is a Multiple-Document Interface (MDI) application. I add a HandleException in Program.cs so that when the application throws an exception, I'm able to log it in the log file. But if I get an exception in an ApplicationService, this exception is handled by ABP and not thrown back to WinForms, and nothing is written in the log file.
Do I need to implement some interface to have the classic logging like MVC/Angular app?
UPDATE
I found that the problem is related to async operation. Usually I call:
await _service.GetProducts();
If an exception is thrown, the main thread does not intercept it. If I switch to:
AsyncHelper.RunSync(() => _service.GetProducts());
Then the main thread intercepts the error.

because the exception is thrown in another thread you have to handle unhandled exceptions of the application domain. insert the exception handler into the starting point of your application. for win forms i guess you can use program.cs
static class Program
{
[STAThread]
static void Main(string[] argv)
{
try
{
AppDomain.CurrentDomain.UnhandledException += (sender,e)
=> HandleException(e.ExceptionObject);
Application.ThreadException += (sender,e)
=> HandleException(e.Exception);
Application.Run(new MainWindow());
}
catch (Exception ex)
{
HandleException(ex);
}
}
static void HandleException(object exception) {
var ex= exception as Exception;
if (ex== null) {
ex= new NotSupportedException("Unhandled exception: " + exceptionObject.ToString());
}
//you can log exception here -> ex.ToString();
}
}

Ok after some invastigation and googling I found this MSDN explanation Asynchronous Programming - Async from the Start
Accoriding to this article I change my program start to move to async code.
I need to chage a little bit more because I'm on Mdi Form when open a inside form
Form1 childForm = Globals.Bootstrapper.IocManager.Resolve<Form1>();
childForm.MdiParent = this;
var formAsync = childForm.InitializeAsync();
FormExtension.HandleExceptions(formAsync);
childForm.Show();
I add the static class to intercept the error form Abp
public static async void HandleExceptions(Task task)
{
try
{
await Task.Yield(); //ensure this runs as a continuation
await task;
}
catch (Exception ex)
{
//deal with exception, either with message box
//or delegating to general exception handling logic you may have wired up
//e.g. to Application.ThreadException and AppDomain.UnhandledException
var log = Globals.Bootstrapper.IocManager.IocContainer.Resolve<ILogger>();
LogHelper.LogException(log, ex);
//Exception handling...
MessageBox.Show("Ops!" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
//Application.Exit();
}
}
Now my log file is populated in correct way

Related

How can I handle all possible exceptions when I do a POST with EF6 / SQL Server 2012

I am using the following code in my controller when I submit a new entry:
// POST /api/Content/
public HttpResponseMessage PostContent(Content content)
{
try
{
content.ModifiedDate = DateTime.Now;
_uow.Contents.Add(content);
_uow.Commit();
var response = Request.CreateResponse<Content>(HttpStatusCode.Created, content);
return response;
}
catch (DbUpdateException ex)
{
return Request.CreateErrorResponse(HttpStatusCode.Conflict, ex);
}
}
This only picks up DbUpdateExceptions so if there is another kind of exception then I think I need to handle it differently.
Can anyone suggest how I should handle other exceptions?
You can add several catch in a row going from the most particular to most general
try
{
content.ModifiedDate = DateTime.Now;
_uow.Contents.Add(content);
_uow.Commit();
var response = Request.CreateResponse<Content>(HttpStatusCode.Created, content);
return response;
}
catch (DbUpdateException ex)
{
return Request.CreateErrorResponse(HttpStatusCode.Conflict, ex);
}
catch (Exception ex)
{
// do what you want
}
If we want to move from quick-and-dirty method to longer-but-safer, we may pass following steps:
Excapsulate data access in separate object and handle it's exceptions in it, passing to the outside world custom exceptions. You may decide to hide all data access exceptions under single custom exception.
(as #Massanu pointed) Concatenate handlers starting with most particular to most general. To react approprietely on different exceptions, do not use single catch (Exception ex) handler.
If something, actually, let unhandled, you may catch it in Application_Error method of global.asax: http://msdn.microsoft.com/ru-ru/library/24395wz3(v=vs.100).aspx
There is a good chapter about error handling in Code Complete book written by Steve Macconell: http://cc2e.com/

Duplex channel callback calls method that throws exception. Where does the execption go?

And how can I present it to the user?
This post : WCF Duplex: How to handle thrown exception in duplex Callback is very close to my scenario. And this post is useful for helping me re-establish the connection when the channel is faulted.
I have a Publishing application Pub, and a subscribing WPF application Sub. The Pub sends a message and the Sub has subscribed for a callback using a duplex channel.
Sub.ViewModel.ReactToChange(sender, e) tries to read some data, but is unable to and throws an exception.
DispatcherUnhandledException doesn't catch it (I didn't really expect it to.)
AppDomain.CurrentDomain.UnhandledException doesn't catch it (that does surprise me)
The end result is I have an application that is still running, and no exception message is shown to the user so they can correct the problem. Is there a way I can show that exception to the user?
This is a bit tricky, but the only way I've found. I hope this helps others.
The idea is to not let an exception get thrown, but instead create an UnhendledExceptionEventArg and pass it up to your UI layer. Here is some example code:
public class BuggySubscriber : IDisposable
{
public BuggySubscriber(string dataSourceName)
{
SyncContext = SynchronizationContext.Current;
Subscriber = new MockSubscriber(dataSourceName);
Subscriber.Refreshed += OnDataChanged;
}
public SynchronizationContext SyncContext { get; set; }
public event EventHandler<UnhandledExceptionEventArgs> ExceptionOccurred;
// Bouncing Exception Step 3
private void OnExceptionOccured(Exception ex)
{
var callback = new SendOrPostCallback(delegate
{
var handler = ExceptionOccurred;
if (!ReferenceEquals(handler, null))
handler(this, new UnhandledExceptionEventArgs(ex, true));
});
SyncContext.Post(callback, null);
}
void OnDataChanged(object sender, ServiceModel.DataChanged.DataChangedEventArgs e)
{
// Bouncing Exception Step 1 & 2
OnExceptionOccured(new NotImplementedException());
}
So this is the "Sub" code. In the WPF application I add the following when the app starts:
protected override void OnStartup(StartupEventArgs e)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
BuggySubscriber.ExceptionOccurred += Sub_ExceptionOccurred;
...
}
// Bouncing Exception Step 5
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var exception = e.ExceptionObject as Exception;
if (!ReferenceEquals(exception, null))
ShowErrorMessage(exception);
}
// Bouncing Exception Step 4
void Sub_ExceptionOccurred(object sender, UnhandledExceptionEventArgs e)
{
var exception = e.ExceptionObject as Exception;
if (!ReferenceEquals(exception, null))
throw exception;
}
So now let's try to follow the bouncing exception.
In real life, the subscriber was notified and an exception occurs and is caught. (In my sample, I don't show that.)
Then the OnExceptionOccurred(Exception ex) is called.
That then creates the SendOrPostCallback using the ExceptionOccurred event and then does a Post to the current SynchronizationContext.
The WPF application that registered for the ExceptionOccurred (Now if you like, you could handle the exception message here... I chose to use two paths for exceptions rather than three.) It casts and throws the Exception.
Now the CurrentDomain_UnhandledException processes it and shows an error message to the user (right before it exits).
I'm sure there are many variations on this, but this does show some of the trickier code that I could not find in one place.
NOTE: This does not solve any channel problems. If you have an exception you can recover from you will still need to reestablish the channel since it will be faulted or closed.

registering UnhandledException of AppDomain WPF

I am registering to un-handled exception of my WPF Application.
After UnhandledExceptionHandler invokes, the application will close automatically ? Or do I need to call ShutdownProcess();
Is this enough ?
static void Main(string[] args)
{
//Register to unhandled exception for this application
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)
{
try
{
Exception ex = (Exception)args.ExceptionObject;
_logger.ErrorFormat("Process caught unhandled exception, Exception = {0}", ex);
ShutdownProcess();
}
catch
{
// swallow silently... nothing we can do.
}
}
From MSDN:
"This event provides notification of uncaught exceptions. It allows
the application to log information about the exception before the
system default handler reports the exception to the user and
terminates the application."
So the ugly Popup will be displayed regardless what you are doing in your Handler and the application will be terminated after that.
If you don't want the default error popup to be displayed you should add a handler to Application.Current.DispatcherUnhandledException log your errors and call Application.Current.Shutdown() yourself.

WPF handling missing dlls

I have noticed that in some situations, where I do not distribute a particular dll, which is required by application, the application doesn't not provide any errors, it just does not load (show on screen). It behaves like you haven't started it.
Does anyone know why is this happening?
Edit: Steps to reproduce:
Create a solution with WPF app project and class library project (ReferenceDll).
Add reference in WPF app project to class library project.
In class library, add this method to Class1
public int Calculate(int a, int b)
{
return a + b;
}
place this code in App.OnStartup:
try
{
int result = new ReferenceDll.Class1().Calculate(2, 4);
}
catch (Exception ex)
{
File.WriteAllText(#"D:\Test\error.txt", ex.ToString());
}
build the solution then remove the ReferenceDll from the bin folder. Run the app.
No file will be created, app will not show. Even if you move Try catch code in the main view, in some button click event, Catch{} will never be fired and it will display non-informative message
AppName has stopped working.
and offer options to debug, which is of no use to end-user.
If you don't have any Trace.WriteLine statements, then I suggest you add some. Add some to the exception handlers. Also you could use the following free tool to capture trace and try and narrow it down that way.
http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx
You could also override the Onstartup method in app.xaml.cs and instantiate your application from there and catch any exceptions and output to trace.
Update
I have tried the steps that you have indicated in your update and the application loaded without any problems. The next thing that I would suggest would be to check what version of the .net framework that you have on your environment that you have deployed to. Look at this link, if you need help to do that:
http://msdn.microsoft.com/en-us/kb/kbarticle.aspx?id=318785
Update
Put your error logging in a handler like the one in the answer to this question and you will see the error. Just tried this with your example and it worked. The error tells you exactly what is wrong:
System.IO.FileNotFoundException: Could not load file or assembly 'ReferenceDll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
File name: 'ReferenceDll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
at WPFApp.App.OnStartup(StartupEventArgs e)
at System.Windows.Application.<.ctor>b__1(Object unused)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog
WPF window crashes on startup, or it starts but hangs and does not render contents
That may happen when the exception is thrown on a secondary thread. See remarks section on this page:
Standalone or browser-hosted WPF applications use the Application class to detect unhandled exceptions (see DispatcherUnhandledException). However, Application can only detect unhandled exceptions that are thrown on the same thread that the Application class is running. Usually, an application will have one main user interface (UI) thread, so the unhandled exception detection behavior of the Application class is adequate. However, unhandled exceptions that are thrown on secondary threads are not automatically detected by the Application class on the main UI thread.
You can try using this event to catch detect the exception and log the error:
AppDomain.UnhandledException Event
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
static void MyHandler(object sender, UnhandledExceptionEventArgs args) {
Exception e = (Exception) args.ExceptionObject;
Console.WriteLine("MyHandler caught : " + e.Message);
}
UPDATE:
Apart from the threading issue it also can the cause if you put your try...catch block to the wrong place. Consider this example:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Do();
}
private void Do()
{
try
{
int result = new ClassLibrary1.Class1().Calculate(2, 4);
}
catch (System.Exception ex)
{
Console.WriteLine("MyHandler caught by try...catch: " + ex.Message);
}
}
}
This will result in an exception at the line where the Do() is called since the CLR here tries to resolve the assembly at this point. The exception is not caught and the app terminates.
But if you try this one:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
try
{
Do();
}
catch (System.Exception ex)
{
Console.WriteLine("MyHandler caught by try...catch: " + ex.Message);
}
}
private void Do()
{
int result = new ClassLibrary1.Class1().Calculate(2, 4);
}
}
The output is:
MyHandler caught by try...catch: Could not load file or assembly 'ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
Note that the UnhandledException event is not fired when you subscribe to it in the same function where the assembly is referenced. This works as well:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(
(sender, args) =>
{
Exception ex = (Exception)args.ExceptionObject;
Console.WriteLine("MyHandler caught by UnhandledException handler: " + ex.Message);
});
Do();
}
private void Do()
{
int result = new ClassLibrary1.Class1().Calculate(2, 4);
}
Result:
MyHandler caught by UnhandledException handler: Could not load file or assembly 'ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
Hope it helps.

Exit Application On Error in a C # Library

It is a silly question I admit. So, apologies if this wastes your time but I just cannot find out a solution.
A WinForm Application which has a Class Library. I use Log4Net dll for logging information.
On Button_Click, I call a function in the Class Library which might throw an error. So, I have the contents of the function inside a try-catch-finally block. In the catch, I write log statements (using Log4Net dll).
Now, that an error has occurred, I want a Message to be shown to the UI. And after a Message is shown, I want it to quit.
How do I pass the control from the catch block of the Class Library back to the Form code so that I display a message and then quit?
Just call throw without any parameters after you've logged the error in the exception handler in the class library and it'll rethrow the exact same exception with the same callstack etc.
Then let your form catch it and handle it as you want.
In the Class Library Method, in the catch, rethrow the exception, so that it can bubble up to the form.
In the form Button_Click wrap the Class Method call in a try catch, and in the catch display the message and exit.
The library should probably re-throw the exception after logging about it.
class Form
{
OnClick()
{
try
{
library.Routine();
}
catch(Exception e)
{
// messagebox
// exit
}
}
}
class Library
{
public void Routine()
{
try
{
// stuff
}
catch(Exception e)
{
logger.error("error in routine", e);
throw;
}
}
}

Resources