在Web API中尝试/捕获块/避免异常不是一个好主意吗?

时间:2018-11-13 18:35:14

标签: c# exception asp.net-core asp.net-core-webapi

我已经读过(here),执行Try / Catch块并避免Web API设置中的异常不是一个好主意。但是,如果您想捕获并记录应用程序中发生的错误,那么尝试/捕获不是解决问题的最佳方法吗?这是我在应用程序中所做的一个示例-我很好奇是否有人有更好的方法。我的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"
                });
            }
        }
    }
}

2 个答案:

答案 0 :(得分:1)

我有一些建议:

  1. 尽可能避免使用try..catch。例如,使用诸如TryParseTryCreate等的方法,而不是引发异常的方法。 *OrDefault LINQ方法也是如此,例如始终使用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;
    }
    
  4. 将错误处理与请求处理分开。您的应用只需要返回请求的响应。它不应该在意诸如向管理员发送电子邮件之类的东西。您需要某种记录,指出发生了问题,这是可以理解的,但是简单的日志记录就足以解决问题,而且重量更轻。如果您想向管理员发送电子邮件,则可以设置单独的服务以在适当时监视日志和生成电子邮件,从而适当地带走该过程。

答案 1 :(得分:1)

如果您想捕获异常并对异常做一些常规的事情,例如您在示例中所做的,那么您的方式不是ASP.NET中的好方法:)

当您有多个控制器并且每个控制器内部都有多个动作时,您将有很多代码重复。

ASP.NET Core允许您创建一个Filter,您可以在其中放置所有此类逻辑。这意味着您将只拥有一个地方来处理未捕获的异常。 您应该彻底了解IExceptionFilter

所提供的可能性