Global Error Handling in ASP.NET Web API 2(webapi2 中的全局异常处理)

时间:2021-09-18 22:16:57

  目前,在Web API中没有简单的方法来记录或处理全局异常(webapi1中)。一些未处理的异常可以通过exception filters进行处理,但是有许多情况exception filters无法处理。例如:

   1.从控制器构造函数中抛出的异常。

  2.从message handlers中抛出的异常。

  3.路由过程中抛出的异常。

  4.响应内容序列化过程中引发的异常。

  

  我们希望提供一种简单、一致的方法来记录和处理这些异常(如果可能的话)。

  处理异常主要有两种情况,一种是我们可以发送错误响应,另一种是我们只能记录异常。

  后一种情况的一个例子是在流式响应内容中间抛出异常时;在这种情况下,发送新的响应消息太晚了,因为状态代码、头部和部分内容已经边界,所以我们只能简单地中止连接。即使无法处理异常以产生新的响应消息,我们应该仍然支持记录异常。在我们能够检测到错误的情况下,我们可以返回一个适当的错误响应,如下所示:

public IHttpActionResult GetProduct(int id)

{

  var product = products.FirstOrDefault((p) => p.Id == id);

  if (product == null) { return NotFound(); } return Ok(product);

}

现有选项

  除了现有的exception filters之外,message handlers现在还可以用来观察所有500-level responses,但是对这些响应采取行动是困难的,因为它们缺乏关于原始错误的上下文。message handlers对于它们能够处理的情况也有一些与exception filters相同的限制。虽然Web API确实具有捕获错误条件的跟踪基础结构,但是跟踪基础结构用于诊断目的,并且不是为生产环境设计也不适合在生产环境中运行。全局exception handling and logging应该才是可以在生产期间运行并插入现有监视解决方案(例如,ELMAH)的服务。

新的解决方案概述(webapi2)

  我们提供两个新的用户可替换的服务,即 IExceptionLogger and IExceptionHandler,用来记录和处理未处理的异常。这两个服务非常相似,有两个主要区别:

  1、我们支持注册多个exception loggers,但只支持一个exception handler。

  2、Exception loggers总是被调用,即使我们即将中止连接。只有当我们仍然能够选择要发送的响应消息时,才会调用exception handler。

  两个服务都提供对异常上下文的访问,该异常上下文包含从检测到异常的点开始的相关信息,特别是HttpRequestMessage、HttpRequestContext、抛出的异常和异常源(以下详细信息)。

一、使用原则

  因为在小版本中添加了该功能,所以没有破坏性的改变,影响解决方案的一个重要约束是,没有任何破坏性的改变,无论是合同类型还是行为方式。这个约束排除了我们希望针对将异常转换为500个响应的现有捕获块进行的一些清理。这个额外的清理是我们可以考虑的后续重大释放。如果这对你很重要,请在ASP.NET Web API用户语音上投票。

  保持与Web API构造的一致性是Web API的过滤器流水线处理横切关注点的好方法,该关注点具有在操作特定的、控制器特定的或全局范围内应用逻辑的灵活性。

  包括exception filters在内的筛选器总是具有action和controller上下文,甚至在全局范围内注册时也是如此。该契约对于过滤器(filters)是有意义的,但是它意味着exception filters,甚至是全局范围的exception filters,对于某些异常处理情况(如message handlers中的异常,其中不存在action或controller上下文)并不适合。

  如果我们想使用过滤器(filters)提供的灵活范围来进行异常处理,我们仍然需要exception filters。但是,如果我们需要在controller context之外处理异常,那么我们还需要一个单独的结构用于完全的全局异常处理(一些没有控controller context和action context约束的构造)。

二、使用场景

  1、Exception loggers

    是解决Web API捕获的所有未处理异常的解决方案。

  2、Exception handlers

    是为Web API捕获的未处理异常定制所有可能的响应的解决方案。

  3、Exception filters

    是处理与特定action或controller相关的子集未处理异常的最简单的解决方案。

三、使用详情

  ExceptionLogger和ExceptionHandler接口是采用各自Context的简单异步方法:

public interface IExceptionLogger
{
  Task LogAsync(ExceptionLoggerContext context,
  CancellationToken cancellationToken);
}

public interface IExceptionHandler
{
  Task HandleAsync(ExceptionHandlerContext context,
  CancellationToken cancellationToken);
}

  我们还为这两个接口提供基类。Overriding(重写)核心(sync or async)方法是在建议的时间内记录或处理所需的全部。对于日志记录,ExceptionLogger基类将确保每个异常只调用一次核心logging方法(即使稍后它在调用堆栈上进一步传播并再次被捕获)。ExceptionHandler基类将只针对调用堆栈顶部的异常调用核心处理方法,忽略遗留嵌套的捕获块。(这些基类的简化版本在下面的附录中。)IExceptionLogger和IExceptionHandler都通过ExceptionContext接收关于异常的信息。

public class ExceptionContext
{
public Exception Exception { get; set; }

public HttpRequestMessage Request { get; set; }

public HttpRequestContext RequestContext { get; set; }

public HttpControllerContext ControllerContext { get; set; }

public HttpActionContext ActionContext { get; set; }

public HttpResponseMessage Response { get; set; }

public string CatchBlock { get; set; }

public bool IsTopLevelCatchBlock { get; set; }
}

。。。。。。。。。。。。。。。。。。。。。。。。。未完。。。。。。。。。。。。。。。。。。。。。。

For both exception loggers and exception handlers, we don't do anything to recover if the logger or handler itself throws an exception. (Other than letting the exception propagate, leave feedback at the bottom of this page if you have a better approach.) The contract for exception loggers and handlers is that they should not let exceptions propagate up to their callers; otherwise, the exception will just propagate, often all the way to the host resulting in an HTML error (like the ASP.NET's yellow screen) being sent back to the client (which usually isn't the preferred option for API callers that expect JSON or XML).

  对于exception loggers和exception handlers,如果logger或handler本身抛出异常,则不执行任何恢复操作(除了让这个exception传递之外)

  exception  loggers和handlers的约定:它们不应该让异常传递到调用者;否则,异常将只是传递,通常服务器出现错误后一个HTML的错误(如ASP.NET的黄色屏幕)会被发送回客户端(这对于希望使用JSON或XML的API调用者通常不应该这样做)。

使-用-实-例

(也可以参考GIT上作者为Tiago Santos的代码示例:https://github.com/taigosantos/AspNet-WebApi)

  

一、Tracing Exception Logger

  下面的异常记录器将异常数据发送到配置的跟踪源(包括VisualStudio中的调试输出窗口)。

class TraceExceptionLogger : ExceptionLogger
{
  public override void Log(ExceptionLoggerContext context)
  {
    Trace.TraceError(context.ExceptionContext.Exception.ToString());
  }
}

  

二、Custom Error Message Exception Handler

下面的内容对客户端产生自定义错误响应,包括用于联系支持的电子邮件地址。

class OopsExceptionHandler : ExceptionHandler
{
  public override void Handle(ExceptionHandlerContext context)
  {
    context.Result = new TextPlainErrorResult
    {
      Request = context.ExceptionContext.Request,
      Content = "Oops! Sorry! Something went wrong." +"Please contact support@contoso.com so we can try to fix it."
    };
  }

  private class TextPlainErrorResult : IHttpActionResult
  {
    public HttpRequestMessage Request { get; set; }

    public string Content { get; set; }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
      HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
      response.Content = new StringContent(Content);
      response.RequestMessage = Request;
      return Task.FromResult(response);
    }
  }
}

Registering Exception Filters

如果使用“ASP.NET MVC 4 Web应用程序”项目模板创建项目,请将Web API配置代码放在WebApiConfig类中,位于App/_Start文件夹中:

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    config.Filters.Add(new ProductStore.NotImplExceptionFilterAttribute());

    // Other configuration code...
  }
}

附录:以下为基类的实现细节

public class ExceptionLogger : IExceptionLogger
{
public virtual Task LogAsync(ExceptionLoggerContext context,
CancellationToken cancellationToken)
{
if (!ShouldLog(context))
{
return Task.FromResult(0);
}

return LogAsyncCore(context, cancellationToken);
}

public virtual Task LogAsyncCore(ExceptionLoggerContext context,
CancellationToken cancellationToken)
{
LogCore(context);
return Task.FromResult(0);
}

public virtual void LogCore(ExceptionLoggerContext context)
{
}

public virtual bool ShouldLog(ExceptionLoggerContext context)
{
IDictionary exceptionData = context.ExceptionContext.Exception.Data;

if (!exceptionData.Contains("MS_LoggedBy"))
{
exceptionData.Add("MS_LoggedBy", new List<object>());
}

ICollection<object> loggedBy = ((ICollection<object>)exceptionData[LoggedByKey]);

if (!loggedBy.Contains(this))
{
loggedBy.Add(this);
return true;
}
else
{
return false;
}
}
}

public class ExceptionHandler : IExceptionHandler
{
public virtual Task HandleAsync(ExceptionHandlerContext context,
CancellationToken cancellationToken)
{
if (!ShouldHandle(context))
{
return Task.FromResult(0);
}

return HandleAsyncCore(context, cancellationToken);
}

public virtual Task HandleAsyncCore(ExceptionHandlerContext context,
CancellationToken cancellationToken)
{
HandleCore(context);
return Task.FromResult(0);
}

public virtual void HandleCore(ExceptionHandlerContext context)
{
}

public virtual bool ShouldHandle(ExceptionHandlerContext context)
{
return context.ExceptionContext.IsOutermostCatchBlock;
}
}

具体请参考:https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/web-api-global-error-handling

Global Error Handling in ASP.NET Web API 2(webapi2 中的全局异常处理)的更多相关文章

  1. Exception Handling in ASP&period;NET Web API webapi异常处理

    原文:http://www.asp.net/web-api/overview/error-handling/exception-handling This article describes erro ...

  2. Exception Handling in ASP&period;NET Web API

    public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErr ...

  3. ASP&period;NET Web API Basic Identity 中的基本身份验证

    缺点 用户凭证在请求中发送. 凭据作为明文发送. 每个请求都会发送凭据. 无法注销,除非结束浏览器会话. 易于跨站点请求伪造(CSRF); 需要反CSRF措施. 优点 互联网标准. 受所有主要浏览器支 ...

  4. ASP&period;NET Web API 异常日志记录

    如果在 ASP.NET MVC 应用程序中记录异常信息,我们只需要在 Global.asax 的 Application_Error 中添加代码就可以了,比如: public class MvcApp ...

  5. ASP&period;NET Web API 2中的错误处理

    前几天在webapi项目中遇到一个问题:Controller构造函数中抛出异常时全局过滤器捕获不到,于是网搜一把写下这篇博客作为总结. HttpResponseException 通常在WebAPI的 ...

  6. &lbrack;翻译&rsqb;ASP&period;NET Web API 2 中的全局错误处理

    目录 已存在的选项 解决方案预览 设计原则 什么时候去用 方案详情 示例 附录: 基类详情 原文链接 Global Error Handling in ASP.NET Web API 2 由于翻译水平 ...

  7. ASP&period;NET Web API之消息&lbrack;拦截&rsqb;处理

    标题相当难取,内容也许和您想的不一样,而且网上已经有很多这方面的资料了,我不过是在实践过程中作下记录.废话少说,直接开始. Exception 当服务端抛出未处理异常时,most exceptions ...

  8. 【ASP&period;NET Web API教程】4&period;3 ASP&period;NET Web API中的异常处理

    原文:[ASP.NET Web API教程]4.3 ASP.NET Web API中的异常处理 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本系列教程,请先看前面的内 ...

  9. ASP&period;NET Web API之消息&lbrack;拦截&rsqb;处理(转)

    出处:http://www.cnblogs.com/Leo_wl/p/3238719.html 标题相当难取,内容也许和您想的不一样,而且网上已经有很多这方面的资料了,我不过是在实践过程中作下记录.废 ...

随机推荐

  1. C&num;构造函数在继承时必须要求与父类型构造函数入参相同怎么办?

    摘要 我们都知道,C#中,在类型继承时,由于构造子类必须先构造其父类型的内容,因此,必须子类型的构造函数中调用父类型的构造函数(无参数的不需要显式声明). 但是往往我们会出现,子类型本身的构造函数大于 ...

  2. MVC中使用Tuple完成匿名类数据存储

    使用MVC时,会遇到从Controller传递到View的数据只是某几个表中的几个字段的数据,有很多人都会想到能否把这几个字段组成一个匿名类传到View,但是这样好像行不通,所以有些时候我们会针对这几 ...

  3. fpm来制作rpm包

    转自 http://blog.halfss.com/blog/2013/02/26/fpmbao-guan-li/ 另查看 http://my.oschina.net/lxcong/blog/1438 ...

  4. HDU5886 Tower Defence 【两遍树形dp】【最长链预处理】

    题意:N个点的一棵带权树.切掉某条边的价值为切后两树直径中的最大值.求各个边切掉后的价值和(共N-1项). 解法一: 强行两遍dp,思路繁琐,维护东西较多: dis表示以i为根的子树的直径,dis2表 ...

  5. Lars Knoll 宣布了Qt 5有四大目标

    作者:廖梓跃链接:http://www.zhihu.com/question/19636309/answer/13097572来源:知乎著作权归作者所有,转载请联系作者获得授权. 自诺基亚宣布转向Wi ...

  6. 201521123111《Java程序设计》第8周学习总结

    1. 本章学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 附上ppt: 1.2 选做:收集你认为有用的代码片段 List strList = new ArrayList ...

  7. iOS字体大小

    1,iOS 字体大小单位是pt——磅. 英文字体的1磅,相当于1/72 英寸,约等于1/2.8mm. px:相对长度单位.像素(Pixel).(PS字体) pt:绝对长度单位.点(Point).(iO ...

  8. JsonTools 工具类

    import net.sf.json.JSONObject; public class JsonTools { public static JSONObject getJSONObject(Strin ...

  9. JETSON TK1 ~ 刷机和克隆固件

    1:PC端的ubuntu. 要求必须是正常系统,不可以使用虚拟机.由于烧写过程采用刷机模式,虚拟机刷机易导致刷机问题. 2:驱动包.文件系统和源码下载 1.Driver package(驱动包,相当于 ...

  10. Html5shiv ---- 让IE低版本浏览器识别并支持HTML5标签

    Html5shiv.js是针对IE浏览器的 javaScript 补丁,作用如题 该脚本的下载链接 使用使在head标签中使用script标签引用即可