1

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?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501

2 Answers2

2

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.

Haukinger
  • 10,420
  • 2
  • 15
  • 28
0

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

    }
}
sharp
  • 1,191
  • 14
  • 39
  • I already have a `Dispatcher.UnhandledException` handler. It catches some exceptions but many others are apparently handled by Prism silently and not reported. It especially misses errors that occur in View constructors. – Robert Harvey Jan 25 '19 at 00:48
  • @RobertHarvey Could you create a small example where and what type of errors doesn't Prism log? – sharp Jan 25 '19 at 07:14
  • We use Dapper for data access. The problem can be easily reproduced by munging one of the SQL statements we provide to Dapper. This usually happens in a View constructor (the constructor for the XAML code-behind partial class), so I would imagine that doing anything that throws an exception there would reproduce the problem (like dividing by zero). – Robert Harvey Jan 25 '19 at 15:43
  • @RobertHarvey Yes I have tested your situation (simple one, dividing by zero). And Prism logging mechanism didn't notice that exception at all. Again, it's because it will log only it's events. I understand your situation, and you currently want to log other exceptions not just prisms one, but since it has it's own logging mechanism, why not use it? You can, and can't. To use extensive logging, from my exp. NLog is suiting most of my needs. But if you want to keep logging with prism ,then you need to use extension methods. I have updated my answer with my small test. – sharp Jan 25 '19 at 21:17
  • Extension methods are just syntactic sugar for static method calls. Why would they be a prerequisite for proper logging? Anyway, it would be fine if Prism just passed-through the exceptions it wasn't interested in instead of swallowing them. I need this thing to fail fast; Prism swallowing all exceptions means I must wrap everything I do in its own try/catch blocks, and that's not something that I signed up for. – Robert Harvey Jan 25 '19 at 21:20
  • @RobertHarvey Exactly, I totally agree with you! But, wouldn't that mean that installing Prism inside any project, the Prism needs to hook to all exceptions? It isn't really designed for that. If other libraries aren't an option, I only can suggest to fork Prism and extend it to suit your needs. I hope I helped in some way. – sharp Jan 25 '19 at 21:28