在 Web API 中执行 Try/Catch 块/避免异常不是一个好主意吗?

JED*_*JED 1 c# exception asp.net-core asp.net-core-webapi

我读过(此处),在 Web API 设置中执行 Try/Catch 块并避免异常并不是一个好主意。但是,如果您想捕获并记录应用程序中发生的错误...... try/catch 不是最好的方法吗?这是我在应用程序中所做的示例 - 我很好奇是否有人有更好的方法。我的ErrorHander班级将错误保存到数据库,并向管理员发送电子邮件详细信息。

控制器

namespace MyApp.Controllers
{
    [Route("api/[controller]")]
    public class AuthController : Controller
    {
        private readonly IAuthRepository _repo;
        private readonly IErrorHandler _errorHandler;

        private AuthController(IAuthRepository repo, IErrorHandler errorHandler) {
            _errorHandler = errorHandler;
        }

        [Authorize]
        [HttpPut("changePassword")]
        public async Task<IActionResult> ChangePassword(
            [FromBody] UserForChangePasswordDto userForChangePasswordDto)
        {
            var userFromRepo = await _repo.Login(userForChangePasswordDto.Username,
                    userForChangePasswordDto.OldPassword, null);

            try
            {
                //logic to update user's password and return updated user

                return Ok(new { tokenString, user });
            }
            catch (Exception ex)
            {
                // emails error to Admin, saves it to DB, then returns HttpStatusCode
                return await _errorHandler.HandleError(
                    HttpStatusCode.InternalServerError, Request, new Error
                {
                    Message = ex.Message,
                    StackTrace = ex.StackTrace,
                    User = userFromRepo != null ? userFromRepo.Username : "Invalid User"
                });
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Chr*_*att 5

我有一些建议:

  1. try..catch尽可能避免。例如,使用TryParseTryCreate等方法,而不是抛出异常的方法。LINQ 方法也是如此*OrDefault,例如始终使用SingleOrDefault而不是 等Single。基本上,如果有一种方法可以完全避免抛出异常,请使用它。

  2. 当您确实需要处理异常时,请在抽象中进行处理,而不是在应用程序代码中进行。例如,大概该//logic to update user's password and return updated user行正在使用您的IAuthRepository. 您调用的存储库方法本身不应引发异常。如果里面的代码抛出异常,就在那里捕获并在那里处理。然后,您的方法本身可以返回类似布尔值的内容,您可以使用它来确定操作是否成功并相应地进行分支。尽管实际的错误处理逻辑(电子邮件管理等)包含在您的IErrorHandler抽象中,但您的应用程序代码仍然使用它并依赖于它,这是不必要的领域知识。

  3. 当你捕获异常时,捕获特定的异常。您应该确切地知道您正在捕获什么以及为什么。捕获通用的东西Exception通常是懒惰编码的标志。您甚至可能根本不知道是否可以返回异常,但您仍在使用性能消耗try..catch块。在某些情况下,捕获任何可能的异常可能是合适的,但是,您应该始终重新抛出异常。吞并所有可能的例外是一个巨大的禁忌。如果您觉得无法重新抛出异常,那么您应该针对特定的异常。

    try
    {
        // do something
    }
    catch (Exception e)
    {
        // log exception
        throw;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 将错误处理与请求处理分开。您的应用程序只需要返回请求的响应即可。它不应该关心诸如向管理员发送电子邮件之类的事情。您需要某种记录来表明出现了问题,这是可以理解的,但简单的日志记录就足够了,而且重量要轻得多。如果您想向管理员发送电子邮件,您可以设置单独的服务来监控您的日志并在适当的时候生成电子邮件,这会将该过程适当地带出。