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

1.1k Views Asked by At

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?

2

There are 2 best solutions below

2
Haukinger On BEST ANSWER

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.

6
sharp On

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

    }
}