C# 我如何确保一个操作赢得';不要破坏整个应用程序?

C# 我如何确保一个操作赢得';不要破坏整个应用程序?,c#,.net,exception,crash,C#,.net,Exception,Crash,我有一个应用程序执行一些额外的工作,如清理旧日志、发送通知等。如果一个作业失败,我不希望整个应用程序停止工作,不执行剩下的作业 那么比如说, await SendUsersBirthdayEmailsAsync(); // <-- if something fails while trying to send birthday emails here, I don't want the app to stop working and not clean logs and so on...

我有一个应用程序执行一些额外的工作,如清理旧日志、发送通知等。如果一个作业失败,我不希望整个应用程序停止工作,不执行剩下的作业

那么比如说,

await SendUsersBirthdayEmailsAsync(); // <-- if something fails while trying to send birthday emails here, I don't want the app to stop working and not clean logs and so on...
await DeleteOutdatedLogsAsync();
await SendSystemNotificationsAsync();

等待SendUsersByrthdayEmailsAsync();// 对可能失败的代码的每个部分使用
try catch
块。
根据需要,使用
try catch finally
block

在每个
catch
块上,根据需要记录异常。我使用Nlog进行日志记录,因此我建议对此进行研究

try{
    //do work here
}
catch(Exception e){
    //log exception here
}
//optional
finally{
    //do optional needed work here
}
大概是这样的:

public bool SendUsersBirthdayEmailsAsync(){
    try{
        SendMail();
    }
    catch(Exception e){
        LogException(e);
    }
    //optional
    finally{
        OptionalWork();
    }       
}
编辑:关于避免使用泛型异常

您始终可以使用多个
catch
块为每种类型的异常定义不同的行为。当您知道可能出现的异常类型时,这非常有用。
例如:

编辑2:用于异常处理

在可能产生异常的代码周围使用
try/catch
块,您的代码可以从该异常中恢复。在
catch
块中,始终将异常从派生度最高的顺序排列到派生度最低的顺序。所有异常都源自
异常
。对于基本异常类,前面有
catch
子句的
catch
子句不会处理更多派生异常。当代码无法从异常中恢复时,不要捕获该异常。如果可能,启用调用堆栈上的方法以进行恢复

使用
语句或最后使用块清理分配给
的资源。更喜欢使用
语句在抛出异常时自动清理资源。最后使用
清理未实现
IDisposable的资源
finally子句中的代码几乎总是在抛出异常时执行


运行此代码表明,在任务内抛出异常不会停止整个程序

如果您已经在使用调度程序执行此任务,为什么不将其拆分为较小的任务?这样一来,如果一个动作失败,它就不会打倒所有其他动作。此外,拥有许多具有专门职责的小型应用程序是一种很好的做法,而不是一个无所不能的通用应用程序。

如果您正在寻找一个可靠的选项来确保流程完成并可跟踪,您可以选择。您还可以通过处理异常来设置重试逻辑,以防失败

由于这些方法的名称表明,这些方法彼此独立,因此只需确保每个方法都返回一个等待的任务,并将它们放入列表中即可。您使用的
wait
表明,他们已经这样做了

在它周围放置一个try catch并捕获AggregateExeption

List<Task> tasks = new List<Task>();
try
{
  tasks.Add(SendUsersBirthdayEmailsAsync());
  tasks.Add(DeleteOutdatedLogsAsync());
  tasks.Add(SendSystemNotificationsAsync());

  Task.WhenAll(tasks); // waits for all tasks to finish
}
catch (Exception e)
{
   //Log e.ToString(); will give you all inner exceptions of the aggregate exception as well, incl. StackTraces, so expect possibly a lot of chars, wherever you log it.
}
List tasks=newlist();
尝试
{
添加(sendUsersBithDayEmailsAsync());
添加(DeleteOutdatedLogsAsync());
添加(SendSystemNotificationsAsync());
Task.WhenAll(tasks);//等待所有任务完成
}
捕获(例外e)
{
//Log e.ToString();还将为您提供聚合异常的所有内部异常,包括StackTraces,因此无论您在何处记录,都可能需要大量字符。
}

这也可能加快速度,因为它们现在是并行运行的。但是,由于它们似乎都在数据库上工作(很可能是相同的),因此,由于调度开销的原因,它们可能不会太多。

您可以使用实现您的方法,并让它们返回布尔值。 让每个方法自己处理异常,这样您就可以确保不会抛出未处理的异常来杀死您的应用程序

如果失败将导致无法恢复的程序状态,则方法应返回false,并且应用程序应以干净的方式自行退出。

未观察到的任务异常 由于您正在使用TaskScheduler,请签出

在即将触发故障任务的未观察到的异常时发生 异常升级策略,默认情况下,将终止 处理


您需要在每个函数中使用Try-Catch,如下所示

try{
    //write your code
}
catch(Exception e){
    //your exception will be here
}
public void insertcity()
{
 try
 {
   //Insert city programming
 }
 catch (exception ex)
 {
   clsLog.InsertLog(ex.Message,"insertCity");
   //do something else you want.
 }        
}
您可以为该异常生成日志文件。 只需为日志文件做一件事。创建日志类和日志文件生成函数。 在所有函数的catch区域中调用该函数

让您创建一个名为clsLog的日志类。和一个名为InsertLog的静态函数(字符串异常,字符串函数名)

在all函数中使用此日志方法,如下所示

try{
    //write your code
}
catch(Exception e){
    //your exception will be here
}
public void insertcity()
{
 try
 {
   //Insert city programming
 }
 catch (exception ex)
 {
   clsLog.InsertLog(ex.Message,"insertCity");
   //do something else you want.
 }        
}
希望它能有所帮助。

所用的-符合我的想法-不过我会再做一件-取消代币-有一个时间限制,你认为多长时间足够-以便一切都完成

等待中的单个任务意味着,当它们分别执行时,它们都会在此时返回到一起。如果发生agreggate异常,您可以捕获它们,然后确定是超时还是需要记录的内容

关于未处理异常和未处理任务异常的两个建议也应该包括在内——无论出于什么原因,它们停止了

我也会考虑将其设置为Windows服务,这样您就可以在启动时将取消令牌传递到任务中,并在服务实际运行时启用计时器,而不是安排任务,然后通过所有异常处理,您可以看到日志随时间的推移告诉您的内容,这比控制台更具弹性应用程序对我来说——但这就是我们通常以这种方式运行任务的方式

您可以在控制台应用程序中启动和停止这样的服务进行测试,然后将其交给一个处理OnStart和OnStop事件的项目。将取消令牌传入OnStop将取消令牌并停止服务循环。

我想如果您使用

try{
    //your nice work
}
catch(Exception e){
    //hmm.. error ok i will show u
}
//optional
finally{
    //again start the operation if u failed here.
}
我也提出了同样的申请,其中一些
public void insertcity()
{
 try
 {
   //Insert city programming
 }
 catch (exception ex)
 {
   clsLog.InsertLog(ex.Message,"insertCity");
   //do something else you want.
 }        
}
try{
    //your nice work
}
catch(Exception e){
    //hmm.. error ok i will show u
}
//optional
finally{
    //again start the operation if u failed here.
}
MyTask().GetAwaiter().GetResult();
await SendUsersBirthdayEmailsAsync().ConfigureAwait(false);