WebAPI 中的 HttpResponseException

  • 你可以在 Action 中使用 HttpResponseException 来包装指定的 HttpCode 和 HttpMessage,如下例子所示:
  1. public Employee GetEmployee(int id)
  2. {
  3. Employee emp = employeeRepository.Get(id);
  4. if (emp == null)
  5. {
  6. var response = new HttpResponseMessage(HttpStatusCode.NotFound)
  7. {
  8. Content = new StringContent("Employee doesn't exist", System.Text.Encoding.UTF8, "text/plain"),
  9. StatusCode = HttpStatusCode.NotFound
  10. }
  11. throw new HttpResponseException(response);
  12. }
  13. return emp;
  14. }
  • 如果你的 Action 返回的是 IHttpActionResult,那么可将 GetEmployee() 方法修改如下:
  1. public IHttpActionResult GetEmployee(int id)
  2. {
  3. Employee emp = employeeRepository.Get(id);
  4. if (emp == null)
  5. {
  6. var response = new HttpResponseMessage(HttpStatusCode.NotFound)
  7. {
  8. Content = new StringContent("Employee doesn't exist", System.Text.Encoding.UTF8, "text/plain"),
  9. StatusCode = HttpStatusCode.NotFound
  10. }
  11. throw new HttpResponseException(response);
  12. }
  13. return Ok(emp);
  14. }

从上面的代码可以看出,错误码 和 错误消息 都赋给了 Response 对象,然后包装到了 HttpResponseException 进行返回。

WebAPI 中使用 HttpError

  • 除了直接实例化 HttpResponseMessage 类,还可以使用 Request.CreateErrorResponse() 快捷的创建 HttpResponseMessage 类,如下代码所示:
  1. public IActionResult GetEmployee(int id)
  2. {
  3. Employee emp = employeeRepository.Get(id);
  4. if (emp == null)
  5. {
  6. string message = "Employee doesn't exist";
  7. throw new HttpResponseException(
  8. Request.CreateErrorResponse(HttpStatusCode.NotFound, message));
  9. }
  10. return Ok(emp);
  11. }

WebAPI 中使用 异常过滤器

  • 异常过滤器是一种可以在 WebAPI 中捕获那些未得到处理的异常的过滤器,要想创建异常过滤器,你需要实现 IExceptionFilter 接口,不过这种方式比较麻烦,更快捷的方法是直接继承 ExceptionFilterAttribute 并重写里面的 OnException() 方法即可,这是因为 ExceptionFilterAttribute 类本身就实现了 IExceptionFilter 接口,如下代码所示:
  1. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
  2. public abstract class ExceptionFilterAttribute : FilterAttribute, IExceptionFilter, IFilter
  3. {
  4. protected ExceptionFilterAttribute();
  5. public virtual void OnException(HttpActionExecutedContext actionExecutedContext);
  6. public virtual Task OnExceptionAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken);
  7. }
  • 下面的代码片段展示了如何通过重写 ExceptionFilterAttribute.OnException() 方法来创建一个自定义异常过滤器,请注意下面的代码是如何捕获在 Action 中抛出的异常,并将捕获到的异常转换为 HttpStatusResponse 实体,然后塞入合适的 httpcode 和 httpmessage,如下代码所示:
  1. public class CustomExceptionFilter : ExceptionFilterAttribute
  2. {
  3. public override void OnException(HttpActionExecutedContext actionExecutedContext)
  4. {
  5. HttpStatusCode status = HttpStatusCode.InternalServerError;
  6. String message = String.Empty;
  7. var exceptionType = actionExecutedContext.Exception.GetType();
  8. if (exceptionType == typeof(UnauthorizedAccessException))
  9. {
  10. message = "Access to the Web API is not authorized.";
  11. status = HttpStatusCode.Unauthorized;
  12. }
  13. else if (exceptionType == typeof(DivideByZeroException))
  14. {
  15. message = "Internal Server Error.";
  16. status = HttpStatusCode.InternalServerError;
  17. }
  18. else
  19. {
  20. message = "Not found.";
  21. status = HttpStatusCode.NotFound;
  22. }
  23. actionExecutedContext.Response = new HttpResponseMessage()
  24. {
  25. Content = new StringContent(message, System.Text.Encoding.UTF8, "text/plain"),
  26. StatusCode = status
  27. };
  28. base.OnException(actionExecutedContext);
  29. }
  30. }
  • 接下来将自定义的异常过滤器添加到 HttpConfiguration 全局集合中,如下代码所示:
  1. public static void Register(HttpConfiguration config)
  2. {
  3. config.MapHttpAttributeRoutes();
  4. config.Routes.MapHttpRoute(
  5. name: "DefaultApi",
  6. routeTemplate: "api/{controller}/{id}",
  7. defaults: new { id = RouteParameter.Optional }
  8. );
  9. config.Formatters.Remove(config.Formatters.XmlFormatter);
  10. config.Filters.Add(new CustomExceptionFilter());
  11. }
  • 除了将自定义异常设置到全局上,你还可以缩小粒度到 Controller 或者 Action 级别上,下面的代码分别展示了如何将其控制在 Action 和 Controller 上。
  1. [DatabaseExceptionFilter]
  2. public class EmployeesController : ApiController
  3. {
  4. //Some code
  5. }
  6. [CustomExceptionFilter]
  7. public IEnumerable<string> Get()
  8. {
  9. throw new DivideByZeroException();
  10. }

ASP.NET Web API 提供了强大的 HttpResponseException 来包装异常信息,默认情况下,当 WebAPI 中抛出异常,系统默认使用 Http StateCode = 500 作为回应,也即:Internal Server Error. ,场景就来了,如果你会用 HttpResponseException 的话,就可以改变这种系统默认行为,自定义错误码和错误信息让结果更加清晰语义化。