如何确保操作不会使整个应用程序崩溃?

kse*_*een 4 .net c# crash exception

我有一个应用程序执行一些其他工作,例如清理旧日志,发送通知等。如果一项工作失败,我不希望整个应用程序停止工作并且不执行剩下的工作。

例如

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();
Run Code Online (Sandbox Code Playgroud)

您会推荐我去哪儿?

Mat*_*att 8

Use try-catch block on every part of the code that can fail.
Depending on what you need, use try-catch-finally block.

On every catch block, log the exception however you want. I use Nlog for logging so i suggest looking into that.

try{
    //do work here
}
catch(Exception e){
    //log exception here
}
//optional
finally{
    //do optional needed work here
}
Run Code Online (Sandbox Code Playgroud)

Something like this:

public bool SendUsersBirthdayEmailsAsync(){
    try{
        SendMail();
    }
    catch(Exception e){
        LogException(e);
    }
    //optional
    finally{
        OptionalWork();
    }       
}
Run Code Online (Sandbox Code Playgroud)

EDIT: About avoiding using generic exception

You can always use multiple catch blocks any define different behavior for each type of exception. This is useful when you know what kind of exception can be expected.
Example:

public bool SendUsersBirthdayEmailsAsync(){
    try{
        SendMail();
    }
    catch (ThreadAbortException tae)
    {
        LogException(tae);
        //do something specific
    }
    catch (ThreadInterruptedException tie)
    {
        LogException(tie);
        //do something specific
    }
    catch(Exception e){
        LogException(e);
    }
    //optional
    finally{
        OptionalWork();
    }       
}
Run Code Online (Sandbox Code Playgroud)

EDIT 2: Official Microsoft guidance for exception handling.

Use try/catch blocks around code that can potentially generate an exception and your code can recover from that exception. In catch blocks, always order exceptions from the most derived to the least derived. All exceptions derive from Exception. More derived exceptions are not handled by a catch clause that is preceded by a catch clause for a base exception class. When your code cannot recover from an exception, don't catch that exception. Enable methods further up the call stack to recover if possible.

Clean up resources allocated with either using statements, or finally blocks. Prefer using statements to automatically clean up resources when exceptions are thrown. Use finally blocks to clean up resources that don't implement IDisposable. Code in a finally clause is almost always executed even when exceptions are thrown.