【问题标题】:How do I get Prism to report the exceptions it traps?如何让 Prism 报告它捕获的异常?
【发布时间】:2019-06-18 15:38:42
【问题描述】:

我有一个 Prism WPF 应用程序在我部署它时未能加载它的一个模块(由于数据库问题)。在我的开发机器上,我可以在 Visual Studio 的输出窗口中看到相关异常被抛出(并且显然被 Prism 捕获和处理)。

我能够通过这样做解决眼前的问题:

public MyModuleViewConstructor()
{
    try
    {
        // some startup work here
        // ...
        InitializeComponent();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString(), "A System Error Occurred.");
    }
}

这会暴露生产中的错误,以便我可以采取行动。但是我仍然想从正常操作过程中抛出的任何异常中获取消息,所以,本着 Prism 做事方式的精神,我这样做了:

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

并在 Bootstrapper 中注册:

class Bootstrapper : DryIocBootstrapper
{
    private readonly Logger _logger = new Logger();

    protected override ILoggerFacade CreateLogger()
    {
        return _logger;
    }
}

这对于调试日志等普通日志条目非常有效。 但它仍然没有记录我的应用程序中抛出的任何异常。

如何让 Prism 在我的应用程序中记录抛出的异常?

【问题讨论】:

    标签: c# wpf exception-handling prism prism-6


    【解决方案1】:

    在导航时,区域管理器会捕获视图和/或视图模型创建期间发生的所有异常。默认情况下不会记录这些内容(尽管这将是一个很酷的功能)。

    但是,您可以收到有关异常的通知并自行记录或做出其他反应。

    为此,请浏览IRegionManager.RequestNavigate( ..., Action<NavigationResult> navigationCallback ) 重载之一。 navigationCallback 将传递一个结果对象,该对象包含NavigationResult.Error 属性中的任何异常。

    【讨论】:

    • 啊,很好的观察力。周一回去工作时我会试试这个。
    • 出于好奇 - 你成功了吗?
    【解决方案2】:

    Prism 日志记录机制主要用于记录与 Prism 事件相关的消息。 要将它用于您的活动,您可以像这样创建和扩展方法

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

    要在您的代码中使用它,您可以执行以下操作

      var logger = _container.Resolve<ILoggerFacade>(); //If you use IoC
      LoggerExtensions.Warn(logger, "Some exception...");
    

    但它仍然没有记录我的应用程序中抛出的任何异常

    我建议在App.xaml.cs 中添加Dispatcher.UnhandledException,这样只要有任何未处理的异常,它就会在那里完成。

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

    更新 #2 我创建了一个小例子,点击按钮将抛出DivideByZeroException。 Prism 日志记录机制根本不知道这个异常。唯一的解决方案是使用扩展方法,扩展异常类或其他库。 我只是没有看到任何其他解决方案。

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

    【讨论】:

    • 我已经有一个Dispatcher.UnhandledException 处理程序。它捕获了一些异常,但许多其他异常显然由 Prism 静默处理且未报告。它尤其遗漏了 View 构造函数中发生的错误。
    • @RobertHarvey 能否创建一个小示例,Prism 不会记录哪些错误以及哪些类型的错误?
    • 我们使用 Dapper 进行数据访问。通过修改我们提供给 Dapper 的 SQL 语句之一,可以很容易地重现该问题。这通常发生在 View 构造函数(XAML 代码隐藏部分类的构造函数)中,所以我认为做任何引发异常的事情都会重现问题(比如除以零)。
    • @RobertHarvey 是的,我已经测试了您的情况(简单的一,除以零)。 Prism 日志记录机制根本没有注意到该异常。同样,这是因为它只会记录它的事件。我了解您的情况,您目前想要记录其他异常,而不仅仅是棱镜之一,但既然它有自己的记录机制,为什么不使用它呢?你可以,也不能。要使用广泛的日志记录,来自我的 exp。 NLog 适合我的大部分需求。但是如果你想用 prism 继续记录,那么你需要使用扩展方法。我已经用我的小测试更新了我的答案。
    • 扩展方法只是静态方法调用的语法糖。为什么它们是正确记录的先决条件?无论如何,如果 Prism 只是通过它不感兴趣的异常而不是吞下它们就可以了。我需要这件事快速失败; Prism 吞并所有异常意味着我必须将我所做的一切都包装在它自己的 try/catch 块中,这不是我注册的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2021-10-23
    相关资源
    最近更新 更多