因此,假设我的应用程序中遇到了未处理的异常,或者由于某种原因崩溃了。 有什么方法让我捕获输出并在应用程序崩溃时显示错误报告对话框。
我在想的是在后台运行一个小程序,唯一的工作就是监听主应用程序的异常退出,然后显示“报告”对话框,用户可以选择通过电子邮件向我发送输出的错误。
不确定如何实现这一点,或者这是否是正确的方法。
报告错误消息将是一项简单的任务,但我不知道如何捕获未处理的异常的输出或获取退出代码(我假设程序在崩溃时会给出除0之外的退出代码)。
在正确的方向上轻推是很棒的。
答案 0 :(得分:12)
你最好的机会在申请中。有两个钩子:
AppDomain.UnhandledException
是最终的“全能”Application.ThreadException
是表单线程“全能”的适当位置取决于您的应用程序语义,很难说您应该知道应用程序的位置。应用程序还需要设置Application.SetUnhandledExceptionMode
。
拥有外部看门狗不太有用,因为它无法提供任何有意义的信息,为什么应用程序崩溃。当它检测到“意外”退出(它是如何知道“意外”?)时,为时已晚,无法收集任何有用的信息。使用内部处理程序,您可以收集异常和堆栈,并将它们提交给像bugcollect.com这样的分析服务,然后您就可以了解现在只有发生了什么,而且它发生的频率以及哪些部署受到影响( 它发生的地方)。还有其他类似的服务,例如exceptioneer.com或Windows Error Reporting(这个服务要求您的代码由Verisign等受信任的授权证书签名)。依靠收集事件的服务远远优于发送邮件,您不想在收件箱中醒来并发现2k事件电子邮件并开始筛选它们以了解发生了什么。
答案 1 :(得分:9)
您可以使用NBug库(也可以使用nuget package here轻松安装)。只需安装NuGet包并进行如下配置:
NBug.Settings.Destination1 =
"Type=Mail;From=me@mycompany.com;To=bugtracker@mycompany.com;SmtpServer=smtp.mycompany.com;";
AppDomain.CurrentDomain.UnhandledException += NBug.Handler.UnhandledException;
Application.Current.DispatcherUnhandledException += NBug.Handler.DispatcherUnhandledException;
现在所有未处理的异常都会被很好地捕获并为您提供礼物包装,您将通过电子邮件获得异常的完整详细信息。使用配置程序工具确保配置正确。
答案 2 :(得分:1)
涉及AppDomain.UnhandledException
事件的答案可能是一个隐式假设,即WPF的UI线程上引发了任何未处理的异常。这意味着,尽管它们通常可以工作,但是在其他线程上使用它们在形式上并不安全。更为可靠的选择是Application.DispatcherUnhandledException
,WPF为应用程序提供了在主UI线程,后台UI线程和BackgroundWorker
实例之间实现对未处理异常的自定义报告的功能。
使用AppDomain.UnhandledException
的可能故障点是报告对话框可能需要单线程单元(STA),因为WPF和Windows窗体都是STA。由于线程池线程默认为多线程单元,因此在报告对话框实例化失败时,将导致Task.Run()
,ThreadPool.QueueUserWorkItem()
,IProgress<T>.Report()
或许多类似的API下的异步操作的未处理异常类似于下面的异常。这会导致应用程序崩溃,而没有机会提示用户报告潜在问题。
System.InvalidOperationException: The calling thread must be STA, because many UI components require this.
at System.Windows.Input.InputManager..ctor()
at System.Windows.Input.InputManager.GetCurrentInputManagerImpl()
at System.Windows.Input.KeyboardNavigation..ctor()
at System.Windows.FrameworkElement.FrameworkServices..ctor()
at System.Windows.FrameworkElement.EnsureFrameworkServices()
at System.Windows.FrameworkElement..ctor()
at System.Windows.Controls.Control..ctor()
at System.Windows.Window..ctor()
我对Application.DispatcherUnhandledException
的经验是,它与Task
一起与TPL结合使用时非常健壮,并且其关联的类有助于将异常传播回调用者。要总结the TPL's exception handling,Wait()
和await
自动重新抛出,使用其他同步方法的呼叫者应检查Task.Exception
。
但是,正如Application.DispatcherUnhandledException
的文档所指出的,其他情况需要WPF的调用方实现异常传播。其中最常见的也许是WPF的Progress<T>
,尽管它的唯一目的是将进度信息从工作线程移回到UI,但它在IProgress<T>.Report()
的实现中却lacks support for propagating exceptions很奇怪。一种解决方法是使用类似于以下示例的方法包装进度更新处理程序。这只是一个草图。对Exception
属性进行更频繁的轮询可能对阻止错误很有用,IDisposable
的语义更强于End()
,并且对于处理积压的情况可能很有用。更新并发失败的方式有所不同。
public class ExceptionPropagatingProgress<TProgress>
{
private readonly Action<TProgress> onProgressUpdateCore;
private readonly IProgress<TProgress> progress;
public Exception Exception { get; private set; }
public ExceptionPropagatingProgress(Action<TProgress> handler)
{
this.Exception = null;
this.onProgressUpdateCore = handler ?? throw new ArgumentNullException(nameof(handler));
this.progress = new Progress<TProgress>(this.OnProgressUpdate);
}
public void End()
{
if (this.Exception != null)
{
throw new AggregateException(this.Exception);
}
}
private void OnProgressUpdate(TProgress value)
{
try
{
this.onProgressUpdateCore(value);
}
catch (Exception exception)
{
lock (this.onProgressUpdateCore)
{
if (this.Exception == null)
{
this.Exception = exception;
}
else
{
this.Exception = new AggregateException(this.Exception, exception);
}
}
}
}
public void QueueProgressUpdate(TProgress value)
{
if (this.Exception != null)
{
throw new AggregateException(this.Exception);
}
this.progress.Report(value);
}
}
答案 3 :(得分:0)
您应该处理Application.ThreadException
事件。