[我知道网上有100个类似的问题,但我仍然无法找到解决这个问题的工作方案,因此发布了。]
我有一个c#Win-Form应用程序。该应用程序用于通过FTP从另一台服务器下载图像。
在任务调度程序的帮助下,应用程序每天运行3次并下载图像,然后自动关闭。
去年它曾经工作正常,但是,从今年年初开始,我们正在从应用程序中获得未处理的异常,例如“请求超时”或“操作超时”。
因此,代替应用程序自动关闭,它会显示一个带有“继续”和“退出”按钮的窗口对话框。
我的要求是,如果抛出任何未处理的异常,应用程序应自动关闭。
我在program.cs中编写了以下代码来处理这个问题。但是,这也没有用,我仍然得到例外窗口。
[STAThread]
static void Main()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
System.Diagnostics.Process proc = System.Diagnostics.Process.GetCurrentProcess();
System.Windows.Forms.Application.Exit();
System.Environment.Exit(0);
proc.Kill();
return;
}
答案 0 :(得分:1)
您可能需要订阅几个事件,以确保捕获每个可能的异常:
Application.ThreadException += yourThreadExceptionHandler;
AppDomain.CurrentDomain.UnhandledException += yourUnhandledExceptionHandler;
TaskScheduler.UnobservedTaskException += yourUnobservedTaskExceptionHandler;
当然,你也应该对程序的主体进行尝试/捕获:
public static void Main()
{
try
{
runProgram();
}
catch (Exception exception)
{
// Your main exception handler.
}
}
您可以使用所有附加处理程序调用的常见异常处理机制,以避免重复代码。 UnobservedTaskException
可能是您想要以不同方式处理的事情(记录它,否则可能忽略)。
答案 1 :(得分:0)
处理未处理的异常是一种痛苦,通常会导致上下文丢失,使得很难知道下一步该做什么。有些方法可以优雅地处理这个问题。
碰巧,我今天写了blog post on the subject。这扩展了通常的异常处理,为您提供了更强大和可预测的执行路径。
它的工作方式是将代码中任何可能失败的部分包装在可以捕获任何异常的内容中,并以可以处理它们的方式将它们包装起来。我这样做的方法是让一个抽象的Fallible
类有三个继承的类Success
,Failure
和BadIdea
。有一个帮助方法可以为您执行此操作,为您留下一个对象,该对象包含您想要的数据,或者您可以用来记录错误,向用户报告等的异常。
抽象类看起来像这样......
public abstract class Fallible<T> {
public static Fallible<T> Do(Func<T> f) {
Fallible<T> result;
try {
T fResult = f();
result = new Success<T> {Value = fResult};
}
catch (BadIdeaException ex) {
result = new BadIdea<T> {Exception = ex};
}
catch (Exception ex) {
// NOTE that in a real application, we would log the exception at this point
result = new Failure<T> {Exception = ex};
}
return result;
}
public void Match(Action<T> onSuccess, Action<Exception> onFailure,
Action<Exception> onBadIdea = null) {
switch (this) {
case Success<T> success:
onSuccess(success.Value);
break;
case BadIdea<T> badIdea:
if (onBadIdea != null) {
onBadIdea(badIdea.Exception);
} else {
onFailure(badIdea.Exception);
}
break;
case Failure<T> failure:
onFailure(failure.Exception);
break;
}
}
}
然后你创建这样的继承类......
public abstract class Fallible<T> {
}
public class Success<T> : Fallible<T> {
public T Value { get; set; }
}
public class Failure<T> : Fallible<T> {
public Exception Exception { get; set; }
}
然后,您可以在Do()方法中包装可能失败的调用,并处理之后发生的事情......
var c = Fallible<Customer>.Do(() => CustomerBll.GetCustomer(id));
c.Match(
c => Customer = c,
e => AlertUser(ex)
);
传递给Match的第一个lambda告诉它在成功的情况下该怎么做,第二个告诉它在失败的情况下该怎么做。
这使您可以更优雅地处理异常。有关详细信息,请参阅博客文章。
这避免了对全局异常处理程序的需要。