How do I get Prism to report the exceptions it traps? - c#

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);
}
}
}

Related

Backup catching for exception thrown in EventHandler

I have a C# Program running as a Windows service doing some Network shenanigans
I thought I had last-ditch "Log Fatal Errors" handling set up. But I've come across an edge case where the Service ends up dead but dodges those catches. :(
I believe this is caused by code throwing an Exception in the EventHandler registered to a .NET library's event.
Obviously I can (andshould!) catch the Exception in my handler, but I'd like to understand how this is avoiding my fall-back error handling, and whether I can add some even more robust fall back logging, to ensure that I have some log records to analyse similar silent bugs in future.
The punchline of relevant code isn't terribly complex:
ServiceBase.Run(container.Resolve<MyProjectWindowsService>()); in a try ...catch in Program.Main()
MyProjectWindowsService : ServiceBase is the service object with an OnStop() implmentation.
NetworkChange.NetworkAvailabilityChanged += CodeThatThrows;
But when that Exception is thrown, neither OnStop() nor the try...catch trigger.
I can get it in a debugger, and it doesn't seem to go anywhere .. it just ... stops.
Fuller program details below, if you want them.
How can I catch and log unhandled exceptions in Event Handlers registered to external library events?
(Also ... Is the behaviour I've described above the expected behaviour, or is there something slightly weird happening?)
Program EXE entry point:
using System;
using System.ServiceProcess;
using Autofac;
using Autofac.Extras.NLog;
using NLog;
namespace MyProject.Service
{
internal static class Program
{
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
/// <summary>
/// The main entry point for the application.
/// </summary>
private static void Main()
{
try
{
// var container = ...DI Setup...
ServiceBase.Run(container.Resolve<MyProjectWindowsService>());
}
catch (Exception ex)
{
Logger.Error(ex, "Unexpected error");
}
finally
{
Logger.Info("==========================");
Logger.Info("WindowsService Stopped (2)");
Logger.Info("==========================");
}
}
}
}
Service Object
using System;
using System.ServiceModel;
using System.ServiceProcess;
using Autofac;
using Autofac.Integration.Wcf;
using NLog;
namespace MyProject.Service
{
public class MyProjectWindowsService : ServiceBase
{
private readonly ILogger _logger;
public DNSProxyWindowsService(ILogger logger)
{
ServiceName = Constants.SERVICE_NAME;
_logger = logger;
}
protected override void OnStart(string[] args)
{
_logger.Info("==============================");
_logger.Info("DNProxy WindowsService Started");
_logger.Info("==============================");
//Other Active setupsteps
}
protected override void OnStop()
{
try
{
//Other Active shutdown steps.
}
catch (Exception ex)
{
_logger.Error(ex, "Could not shut down service tidily");
}
finally
{
_logger.Info("==========================");
_logger.Info("WindowsService Stopped (1)");
_logger.Info("==========================");
}
}
}
}
EventListener Registered to and ultimately invoked:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using NLog;
using Exception = System.Exception;
namespace DNSProxy.Service
{
public class NetworkService
{
public NetworkService()
{
}
public bool NetworkDetectionEnabled
{
set
{
if (value)
{
NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
NetworkChange.NetworkAddressChanged += OnNetworkAddressChanged;
}
else
{
NetworkChange.NetworkAvailabilityChanged -= OnNetworkAvailabilityChanged;
NetworkChange.NetworkAddressChanged -= OnNetworkAddressChanged;
}
}
}
private void OnNetworkAddressChanged(object sender, EventArgs e)
{
CodeThatCanApparentlyThrow();
}
private void OnNetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
CodeThatCanApparentlyThrow();
}
}
}
I unfortunately can only speculate why the exception isn't being caught by your code (and I've kept that speculation to the comments)
However 2 events that might help you are,
AppDomain.UnhandledException - this allows you to register a global handler for any unhandled exceptions in your application. Here is the documentation https://learn.microsoft.com/en-us/dotnet/api/system.appdomain.unhandledexception?view=netframework-4.8
TaskScheduler.UnobservedTaskException - I've included this as I'm not familiar with the internals of the framework libraries you are using, but there maybe some asynchronous code happening somewhere, that is potentially not observing the result of a task. If a faulted task (ie an exception was thrown) is never awaited or never has the Result property accessed and then goes out of scope so it can be garbage collected; at some indeterminate point in the future, it will get collected and an UnobservedTaskException will get thrown. Subscribing to this event, will let you handle that scenario. Documentation here
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskscheduler.unobservedtaskexception?view=netframework-4.8
A little bit dig out what catches what on a WPF application :
var domain = AppDomain.CurrentDomain;
domain.UnhandledException += (o, args) =>
{
Debug.WriteLine("Catched in UnhandledException");
Debug.WriteLine(args.ExceptionObject);
};
domain.FirstChanceException += (o, args) =>
{
Debug.WriteLine("Catched in FirstChanceException");
Debug.WriteLine(args.Exception);
};
TaskScheduler.UnobservedTaskException += (o, args) =>
{
Debug.WriteLine("Catched in UnobservedTaskException");
Debug.WriteLine(args.Exception);
};
Task.Factory.StartNew(async () =>
{
Debug.WriteLine("Workinf");
await Task.Delay(1000);
try
{
throw new Exception("oops");
}
catch (Exception exception)
{
throw new Exception("oopps catched", exception);
}
});
The output will be :
Exception thrown: 'System.Exception' in WpfApp1.exe
Catched in FirstChanceException
System.Exception: oops
at ....
Exception thrown: 'System.Exception' in WpfApp1.exe
Catched in FirstChanceException
System.Exception: oopps catched ---> System.Exception: oops
at ...
--- End of inner exception stack trace ---
at ...
So FirstChanceException will be catching everything (even the handled ones) and the rest won't be catching anything. My suggestion is modifying your example like this:
public class NetworkService
{
private readonly SynchronizationContext currContext;
public NetworkService()
{
this.currContext = SynchronizationContext.Current;
}
private void OnNetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
try
{
CodeThatCanApparentlyThrow();
}
catch (Exception exception)
{
this.currContext.Post(s => throw exception, null); // this will propagate your exception into main thread
}
}
}

How to write events from multiple applications(sources) to the same event log?

I have created a custom event log and would like all my applications to write to the same event log. As you can see below in the image attached, DistributedCOM and Svc Ctrl Mgr are 2 sources writing to the same event log System.
Similarly, I have 2 services that I want to write to the same eventLog.
I tried doing that by creating one event log and passing different source names from the 2 Windows Services that I have created. But I find only one Service writing to the log while the other doesn't.
Below is the class library that I created for Event Log.
public class EventLogger
{
private EventLog eventLog1 = new System.Diagnostics.EventLog();
public EventLogger(string logSource)
{
if (!System.Diagnostics.EventLog.SourceExists(logSource))
{
System.Diagnostics.EventLog.CreateEventSource(logSource, "SampleLog");
}
eventLog1.Source = logSource;
eventLog1.Log = "SampleLog";
}
public void WriteLog(string message)
{
eventLog1.WriteEntry(message);
}
Created 1st Windows Service
public partial class Service1 : ServiceBase
{
private EventLogger.EventLogger eventLog;
public Service1()
{
InitializeComponent();
eventLog = new EventLogger.EventLogger("WinService1");
}
protected override void OnStart(string[] args)
{
try
{
eventLog.WriteLog("Service started in 1st");
}
catch (Exception ex)
{
EventLog.WriteEntry(ex.ToString());
}
}
protected override void OnStop()
{
eventLog.WriteLog("Service stopped");
}
}
Created the 2nd windows Service as well, as above.
public partial class Service2 : ServiceBase
{
private EventLogger.EventLogger eventLog;
public Service2()
{
InitializeComponent();
eventLog = new EventLogger.EventLogger("WinService2");
}
protected override void OnStart(string[] args)
{
try
{
eventLog.WriteLog("Service started in 2nd");
}
catch (Exception ex)
{
EventLog.WriteEntry(ex.ToString());
}
}
protected override void OnStop()
{
eventLog.WriteLog("Service stopped");
}
}
Service1 doesn't seem to log anything, whereas, I can see the logs for Service2. I might be doing a lot of things incorrectly here. Please help me in finding a solution to this. Also, if this can be achieved by using log4Net then solutions with respect to that are welcome as well. thanks in advance.
EDIT: Also, when I try to stop the services, Service 1 fails to stop and throws an error. Image given below.
EDIT 2: Just changed the constructor of the EventLogger class as below and then it worked!! I am not entirely sure if this was the actual cause for the improper functioning. And I'm not quite sure if it had anything to do with the setting of the Log property either. Any light thrown on this by any one of you would be appreciated. I would like to understand better as to what exactly happened here. Thanks.
string logName = "NewLog";
public EventLogger(string logSource)
{
if (!System.Diagnostics.EventLog.SourceExists(logSource))
{
System.Diagnostics.EventLog.CreateEventSource(logSource, logName);
}
eventLog1.Source = logSource;
}

Exception handling for Singleton Events

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.

How to shutdown application while bootstrapper class is still running?

I am using a Prism UnityExtensions bootstrapper class to start my WPF application. How do I shutdown the application while the unityextensions bootstrapper is still running?
See my bootstrapper class below. The SomeClass object may throw a custom exception (fatal). If the custom exception is thrown, I need to close the application. I am using Application.Current.Shutdown() to shutdown the application.
However, the bootstrapper code continues running, and I get a "ResolutionFailedException was unhandled" exception error when setting the datacontext in the CreateShell() method. Obviously, the SomeClass method and interface were not registered with the container due to the catch block.
It appears that the bootstrapper code continues running after a call to Application.Current.Shutdown() was called. I need to stop the bootstrapper code immediately following the call to shutdown.
Any ideas how to shutdown the application without creating the ResolutionFailedException?
ResolutionFailedException exception details -->
Resolution of the dependency failed, type = "SomeClass", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, SomeClass, is an interface and cannot be constructed. Are you missing a type mapping?
public class AgentBootstrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
base.ConfigureContainer();
var eventRepository = new EventRepository();
Container.RegisterInstance(typeof(IEventRepository), eventRepository);
var dialog = new DialogService();
Container.RegisterInstance(typeof(IDialogService), dialog);
try
{
var someClass = new SomeClass();
Container.RegisterInstance(typeof(ISomeClass), SomeClass);
}
catch (ConfigurationErrorsException e)
{
dialog.ShowException(e.Message + " Application shutting down.");
**Application.Current.Shutdown();**
}
}
protected override System.Windows.DependencyObject CreateShell()
{
var main = new MainWindow
{
DataContext = new MainWindowViewModel(Container.Resolve<IEventRepository>(),
Container.Resolve<IDialogService>(),
Container.Resolve<ISomeClass>())
};
return main;
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (Window)Shell;
Application.Current.MainWindow.Show();
}
}
This behaviour occurs, because you´re executing the OnStartup of your Application at this time. I suppose you do it like that:
protected override void OnStartup(StartupEventArgs e)
{
new AgentBootstrapper().Run();
}
The OnStartup has to be completed, before the App can shutdown, so the bootstrapper continues execution. You might throw another exception to get out of the Run():
... catch (ConfigurationErrorsException e)
{
dialog.ShowException(e.Message + " Application shutting down.");
throw new ApplicationException("shutdown");
}
And then catch it in the StartUp():
protected override void OnStartup(StartupEventArgs e)
{
try
{
new AgentBootstrapper().Run();
}
catch(ApplicationException)
{
this.Shutdown();
}
}

How to handle exceptions in wcf service call back

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.

Categories