I am using a singleton pattern for a global event manager class that is not handling exceptions in an acceptable manner.
If an exception is thrown in the code called by one of the events being executed, I always get a Exception has been thrown by the target of an invocation. error. This error contains no information related to the original exception, making it extremely difficult to debug any errors.
Is there some way to pass the original exception information back to the event manager?
public class ApplicationSettings
{
private static EventManager _manager = new EventManager();
public static EventManager EventManager
{
get { return _manager; }
}
}
The event manager class:
public class EventManager
{
public event EventHandler<ReportExecutionArgs> ExecuteReportCurrentPage;
public event EventHandler<ReportExecutionArgs> ExecuteReportNewPage;
public virtual void OnExecuteReportCurrentPage(object sender, ReportExecutionArgs e)
{
try
{
if (this.ExecuteReportCurrentPage != null)
this.ExecuteReportCurrentPage(sender, e);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
public virtual void OnExecuteReportNewPage(object sender, ReportExecutionArgs e)
{
try
{
if (this.ExecuteReportNewPage != null)
this.ExecuteReportNewPage(sender, e);
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
Some other class will handle these events
ApplicationSettings.EventManager.ExecuteReportNewPage += new EventHandler<ReportExecutionArgs>(reportOpenedNewPage);
private void reportOpenedNewPage(object sender, ReportExecutionArgs e)
{
//something in this code throws an error
LitePage page = new LitePage();
_tabs.AddPage(page);
Report report = setReport(page, e);
}
EDIT
Just to clarify, the try/catch blocks in the OnExecuteReport methods are not catching the exception.
A TargetInvocationException such as the one you describe will almost always have the originating exception in it's InnerException.
Related
I'm following on with a tutorial detailing handling events thrown in multiple subscribers to an event. However when the code is run, the TargetInvocationException catch block isn't catching the exceptions thrown in the method body of the subscribers: throw new Exception("Hello") and throw new Exception("World") respectively.
Instead I get an unhandled exception error in the first listener, predictably at throw new Exception("Hello") in private static void AlarmListener.
What is it that I'm doing incorrectly when attempting to catch the invoked method's exceptions?
class AggregatingExceptions
{
public void Main()
{
//create the alarm
AlarmAndLocation alarm = new AlarmAndLocation();
//subscribe the listeners
alarm.OnAlarmRaised += AlarmListener;
alarm.OnAlarmRaised += AlarmListener2;
try
{
alarm.RaiseAlarm("Kitchen");
}
catch (AggregateException agg)
{
foreach (Exception ex in agg.InnerExceptions)
{
Console.WriteLine(ex.Message);
}
}
}
private static void AlarmListener(object sender, AlarmEventArgs e)
{
Console.WriteLine("Alarm listener 1 called.");
throw new Exception("Hello");
}
private static void AlarmListener2(object sender, AlarmEventArgs e)
{
Console.WriteLine("Alarm listener 2 called.");
throw new Exception("World");
}
}
public class AlarmAndLocation
{
public event EventHandler<AlarmEventArgs> OnAlarmRaised = delegate { };
public List<Exception> exceptionList = new List<Exception>();
public void RaiseAlarm(string location)
{
foreach (Delegate handler in OnAlarmRaised.GetInvocationList())
{
try
{
handler.DynamicInvoke(this, new AlarmEventArgs(location));
}
catch (TargetInvocationException ex)
{
exceptionList.Add(ex.InnerException);
}
}
if(exceptionList.Count > 0)
{
throw new AggregateException(exceptionList);
}
}
}
public class AlarmEventArgs : EventArgs
{
public string Location { get; set; }
public AlarmEventArgs(string location)
{
Location = location;
}
}
Supposed I have a class like the below:
public class DisposableClass : IDisposable()
{
private readonly Timer timer;
DisposableClass()
{
this.timer = new Timer(s => cb(s), s, 1000, 1000);
}
Init()
{
try
{
// Do some initialization here that is not done in ctor.
}
catch (Exception)
{
// Log error.
throw;
}
finally
{
// Is this correct?
this.Dispose();
}
}
public void Dispose()
{
this.timer?.Dispose();
}
}
My question is whether the finally clause necessary (or should not have at all) in the above case, of for any non-constructor method when throwing an unhandled exception. Thanks.
EDIT:
In the answer, please address the issues depending on Init() being public,protected, private visibility levels.
I have a Prism WPF application which failed to load one of its modules when I deployed it (due to a database problem). On my development machine, I can see the relevant exceptions being thrown (and apparently caught and handled by Prism) in the Output window of Visual Studio.
I was able to solve the immediate problem by doing this:
public MyModuleViewConstructor()
{
try
{
// some startup work here
// ...
InitializeComponent();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "A System Error Occurred.");
}
}
Which surfaces the error in production so that I can take action on it. But I would still like to obtain the messages from any exceptions that are thrown during normal operations, So, in the spirit of Prism's way of doing things, I did this:
public class Logger : ILoggerFacade
{
public void Log(string message, Category category, Priority priority)
{
using (StreamWriter s = File.AppendText("Log.txt"))
{
s.WriteLine(string.Format("{0}-{1}: {2}", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss.ffff"), priority.ToString(), message));
s.Close();
}
}
}
And registered it in the Bootstrapper:
class Bootstrapper : DryIocBootstrapper
{
private readonly Logger _logger = new Logger();
protected override ILoggerFacade CreateLogger()
{
return _logger;
}
}
This works splendidly for normal log entries such as debug logging. But it still does not log any exceptions thrown within my application.
How do I get Prism to log thrown exceptions in my application?
When navigating, all exceptions that occur during view and/or view model creation are caught by the region manager. Those are not logged by default (although this would be a cool feature).
You can, however, be notified about the exception and log it yourself or react otherwise.
To do that, navigate through one of the IRegionManager.RequestNavigate( ..., Action<NavigationResult> navigationCallback ) overloads. The navigationCallback will be passed a result object that contains any exception in the NavigationResult.Error property.
The Prism logging mechanism is used mostly to log messages related to Prism events.
To use it for your events you could create and extension method like this
public static class LoggerExtensions
{
public static void Warn(this ILoggerFacade loger, string message)
{
using (StreamWriter s = File.AppendText("Log.txt"))
{
s.WriteLine(string.Format(" {0}-{1}: {2}", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss.ffff"), Category.Warn, message));
s.Close();
}
}
}
And to use it inside your code, you could do the following
var logger = _container.Resolve<ILoggerFacade>(); //If you use IoC
LoggerExtensions.Warn(logger, "Some exception...");
But it still does not log any exceptions thrown within my application
I would suggest to add Dispatcher.UnhandledException inside App.xaml.cs, so where ever there is any exception who is not handled, it will finish there.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
this.Dispatcher.UnhandledException += OnDispatcherUnhandledException;
}
void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
//Your code
}
}
Update #2
I have created a small example, where to button click will throw DivideByZeroException. The Prism logging mechanism isn't aware of this exception at all. The only solution would be to use extension method, extend Exception class or other libraries.
I just don't see any other solution.
public partial class ViewA : UserControl
{
ILoggerFacade logger;
public ViewA(ILoggerFacade _logger)
{
InitializeComponent();
logger = _logger;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
var val = 0;
var result = 1500 / val;
}
catch (Exception ex)
{
LoggerExtensions.Warn(logger, ex.Message);
}
}
}
I am having a case where an exception thrown in UI thread doesn't get catched in the calling thread.
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows;
namespace SynchronisationContextAndExceptionWPF
{
public partial class MainWindow : Window
{
private readonly SynchronizationContext _synchronizationContext;
public MainWindow()
{
InitializeComponent();
_synchronizationContext = SynchronizationContext.Current;
}
private void Button_OnClick(object sender, RoutedEventArgs e)
{
try
{
_synchronizationContext.Send(
x =>
{
try
{
DoSomethingOnUiThreadThatThrowsException();
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that threw it.");
throw;
}
}, null);
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw;
}
}
private static void DoSomethingOnUiThreadThatThrowsException()
{
throw new Exception("Any Exception...");
}
}
}
First I thought that cannot possible (all documentation I found said that I can catch exceptions there).
After some reasearch I found the problem: My application uses an UnhandledExceptionHandler. That handles the DispatcherUnhandledException-Event. I am showing some information to the user and set e.Handled = true;:
using System.Diagnostics;
using System.Windows;
using System.Windows.Threading;
namespace SynchronisationContextAndExceptionWPF
{
public partial class App : Application
{
public App()
{
DispatcherUnhandledException += App_DispatcherUnhandledException;
}
private static void App_DispatcherUnhandledException(
object sender,
DispatcherUnhandledExceptionEventArgs e)
{
Debug.WriteLine("Catched Exception in UnhandledExceptionHandler.");
// This line makes the difference:
e.Handled = true;
}
}
}
So the question: why is the DispatcherUnhandledException-Event raised even if I handle it?
How would you solve this situation?
If you have a lot of controls, you can generate a new class which remenbers the special exception variable. So you only need to change the initialization of your _synchronizationContext (hopefully only once at your base class of your controls).
public partial class MainWindow : Window
{
private readonly MySynchronizationContext _synchronizationContext;
public MainWindow()
{
InitializeComponent();
_synchronizationContext = new MySynchronizationContext(SynchronizationContext.Current);
}
private void button_Click(object sender, RoutedEventArgs e)
{
try
{
_synchronizationContext.Send(
x =>
{
DoSomethingOnUiThreadThatThrowsException();
}, null);
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw;
}
}
private static void DoSomethingOnUiThreadThatThrowsException()
{
throw new Exception("Any Exception...");
}
}
class MySynchronizationContext
{
SynchronizationContext innerContext;
public MySynchronizationContext(SynchronizationContext ctx)
{
innerContext = ctx;
}
public virtual void Send(SendOrPostCallback d, object state)
{
Exception threadException = null;
try
{
innerContext.Send(_ =>
{
try
{
d.Invoke(state);
}
catch (Exception exception)
{
threadException = exception;
}
}, null);
}
catch (Exception ex)
{
}
if (threadException != null)
{
throw new Exception("Synchronization error", threadException);
}
}
}
Inside your lambda expression you can set an Exception variable and check this variable later at the calling thread. If it was set, then throw exception at calling thread.
private void button_Click(object sender, RoutedEventArgs e)
{
Exception threadException = null;
try
{
_synchronizationContext.Send(
x =>
{
try
{
DoSomethingOnUiThreadThatThrowsException();
}
catch (Exception ex)
{
Debug.WriteLine("Catched Exception in thread that threw it.");
threadException = ex;
//throw; --> don't throw exception here; otherwise you will get DispatcherUnhandledException twice.
}
}, null);
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw;
}
if(threadException != null)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw threadException; //throw you previously catched exception here.
}
}
Kind Regards,
Daniel
I am trying to log my exceptions with AppDomain.CurrentDomain.UnhandledException.
AppDomain.CurrentDomain.UnhandledException += AppDomainUnhandledException;
public static void AppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
HandleException(e.ExceptionObject as Exception);
}
When I get an exception in the server I will get the fault in the client at debug time but the event hooked to AppDomain.CurrentDomain.UnhandledException will never be fired.
Server:
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class Service : IService
{
public string GetError()
{
throw new ApplicationException();
}
}
Client:
public void GetError()
{
this.service.BeginGetError(OnGetErrorCompleted, null);
}
public void OnGetErrorCompleted(IAsyncResult result)
{
var value = this.service.EndGetError(result);
}
This doesn't work UNLESS I use Distpacher.BeginInvoke..
public void OnGetErrorCompleted(IAsyncResult result)
{
this.Dispatcher.BeginInvoke((Action)(() =>
{
var value = this.service.EndGetError(result);
}));
}
Somebody knows why??
I thought AppDomain.CurrentDomain.UnhandledException would be fired in case of an exception in ANY thread! :S
A better solution is to use something like IErrorHandler and throw FaultExceptions. Decorate your operations to throw FaultExceptions using the FaultContract attribute. Now you can catch specific FaultExceptions at the client. You should not expose exceptions on the server to the client.