1 向客户端发送错误消息

使用throw new HttpResponseException()向客户端抛出错误信息。

HttpResponseException包含两个重载的构造函数,其中一个是构造函数参数类型为HttpResponseMessage,通过其设置状态码,错误消息短语以及消息体内容来向客户端抛出比较详细的错误信息。另一个参数类型为HttpStatusCode,只能设定状态码。

2自定义异常过滤器

扩展IExceptionFilter来定义异常过滤器。异常过滤器不会捕获类型为HttpResponseException的异常,下面的异常也无法被异常过滤器捕获:

1)controller构造器抛出的异常

2)消息处理器抛出的异常

3)路由过程中抛出的异常

4)响应内容序列化与反序列化过程中抛出的异常

代码示例:

public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception!=null)
{
LogHelper.LogError(context.Exception);
}
}
}

3 扩展ExceptionHandler和ExceptionLogger

扩展ExceptionHandler可以捕获大部分异常,包括一些无法被异常过滤器捕获的异常。但是HttpResponseException类型的异常不会被捕获。

示例代码:

/// <summary>
/// 自定义的异常处理程序
/// </summary>
public class GlobalExceptionHandler : ExceptionHandler
{
/// <summary>
/// 处理异常
/// </summary>
/// <param name="context"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public override Task HandleAsync(ExceptionHandlerContext context,CancellationToken cancellationToken)
{
if (!ShouldHandle(context))
{
return Task.FromResult();
}
context.Result = new ErrorResult
{
Request = context.ExceptionContext.Request,
Content = "呀! 有异常,请联系管理员"
};
return Task.FromResult();
}
/// <summary>
/// 判断是否应该处理
/// 后期扩展,重写方法可过滤掉不需处理的异常
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override bool ShouldHandle(ExceptionHandlerContext context)
{
return true;
}
private class ErrorResult : 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);
}
}
}
public class GlobalExceptionLogger : ExceptionLogger
{
public override Task LogAsync(ExceptionLoggerContext context,CancellationToken cancellationToken)
{
if (!ShouldLog(context))
{
return Task.FromResult();
}
if (context.Exception != null)
{
string msg = ClientInfoAnalysis.GetClientInfo();
LogHelper.LogError(context.Exception, msg);
}
return Task.FromResult();
}
/// <summary>
/// 判断是否应记录异常
/// 后期重写此方法,可过滤掉不需要记录的异常信息
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override bool ShouldLog(ExceptionLoggerContext context)
{
if ((context.Exception is System.Web.HttpException))
{
return false;
}
return true;
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// 加载log4net配置文件
LogConfigLoading.Load(AppSettings.Log4netPathForWeb); // 加载Web API服务
config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver(AppSettings.ServicesLocation)); // 全局异常信息处理
config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler()); // 全局异常记录
config.Services.Add(typeof(IExceptionLogger), new GlobalExceptionLogger());
}
}

4某些异常无法被捕获的异常

问题描述

对于在服务加载过程中的异常,无法通过异常过滤器,即实现了System.Web.Http.Filters.IExceptionFilter接口的过滤器来捕获,也不能通过注册ExceptionLogger来达到目的。解决方法如下:

public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
try
{
config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver(SysSettings.ServicesLocation));
}
catch (Exception ex)
{
LogHelper.Error(ex);
} //其他代码
}
}

其中ServiceAssembliesResolver为:

public class ServiceAssembliesResolver : DefaultAssembliesResolver
{
//服务插件路径
private string path;
public ServiceAssembliesResolver(string path):base()
{
this.path = path;
}
public override ICollection<Assembly> GetAssemblies()
{
//获得已有的服务
ICollection<Assembly> baseAssemblies = base.GetAssemblies();
//初始化
List<Assembly> assemblies = new List<Assembly>(baseAssemblies);
//加载每一个服务插件
foreach (string file in Directory.GetFiles(path, "*.dll"))
{
var controllersAssembly = Assembly.LoadFrom(file);
assemblies.Add(controllersAssembly);
} return assemblies;
}
}

但上述方法很可能不起作用,根本原因在于将config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver(SysSettings.ServicesLocation));放入try-catch块中,若ServiceAssembliesResolver在实例化的时候不抛出异常,而是当调用GetAssemblies时抛出异常(例如服务插件存储文件夹被删除),此时无法记录异常。那么问题就在于GetAssemblies方法何时被调用,通过跟踪代码发现Register中的所有代码都执行完成才会加载服务。解决办法是在ServiceAssembliesResolver.GetAssemblies中捕获异常并记录下来。

ASP.NET Web API编程——异常捕获的更多相关文章

  1. ASP.NET Web API编程——路由

    路由过程大致分为三个阶段: 1)请求URI匹配已存在路由模板 2)选择控制器 3)选择操作 1匹配已存在的路由模板 路由模板 在WebApiConfig.Register方法中定义路由,例如模板默认生 ...

  2. ASP.NET Web API编程——序列化与内容协商

    1 多媒体格式化器 多媒体类型又叫MIME类型,指示了数据的格式.在HTTP协议中多媒体类型描述了消息体的格式.一个多媒体类型包括两个字符串:类型和子类型. 例如: text/html.image/p ...

  3. ASP.NET Web API编程——构建api帮助文档

    1 概要 创建ASP.NET Web Api 时模板自带Help Pages框架. 2 问题 1)使用VS创建Web Api项目时,模板将Help Pages框架自动集成到其中,使得Web Api项目 ...

  4. ASP.NET Web API编程——文件上传

    首先分别介绍正确的做法和错误的做法,然后分析他们的不同和错误之处,以便读者在实现此功能时可避开误区 1正确的做法 public class AvaterController : BaseApiCont ...

  5. ASP.NET Web API编程——模型验证与绑定

    1.模型验证 使用特性约束模型属性 可以使用System.ComponentModel.DataAnnotations提供的特性来限制模型. 例如,Required特性表示字段值不能为空,Range特 ...

  6. ASP.NET Web API编程——版本控制

    版本控制   版本控制的方法有很多,这里提供一种将Odata与普通web api版本控制机制统一的方法,但也可以单独控制,整合控制与单独控制主要的不同是:整合控制通过VersionController ...

  7. ASP.NET Web API编程——文件下载

    断点续传基本原理 HTTP协议中与断点续传相关的HTTP头为:Range和Content-Range标头,断点续传实现流程: 1)客户端请求下载一个文件,文件的总长度为n:已经下载了一部分文件,长度为 ...

  8. ASP.NET Web API编程——客户端调用

    可以使用HttpClient这个调用Web API,下面是HttpClient的定义,列举了一些常用的方法,其中还有一些没有列举,包括重载的方法. public class HttpClient : ...

  9. Asp.net Web Api添加异常筛选器

    一.定义一个异常筛选器 using System;using System.Collections.Generic;using System.Linq;using System.Web;using S ...

随机推荐

  1. 2017年12月13日 LinQ用法基本的增删改查

    LinQ是什么? LinQ是语言集成的查询,是用于C#跟Vb的扩展语言 LinQ的用法 新建一个App_Code文件夹,在文件夹下添加一个数据LinQ to SQL类,可以直接直接点击服务器管理器然后 ...

  2. getElementsByName属性

    getElementsByName() 方法可返回带有指定名称的对象的集合 语法 document.getElementsByName(name) 该方法与 getElementById() 方法相似 ...

  3. 学会Markdown,写博客不愁

    前言 Markdown是一种轻量级的标记语言,有John Gruber以及Aaron Hillel Swartz一起编写.Aaron Hillel Swartz是一个极富传奇的黑客,有兴趣可以看看他的 ...

  4. C10K问题摘要

    本文的内容是下面几篇文章阅读后的内容摘要: http://www.kegel.com/c10k.html (英文版) http://www.oschina.net/translate/c10k (中文 ...

  5. JS埋点 小结

    今天在看<大型网站性能监测.分析与优化>一书,提到性能监测方式,才知道有这个名词 “JS埋点”. 大概作用:通过在web页面中,添加js脚本,实现对页面性能监测(如加载时间.服务器响应时间 ...

  6. php从身份证获取性别和出生年月

    //通过身份证号查询出性别与生日 $birth = strlen($idcard)==15 ? ('19' . substr($idcard, 6, 6)) : substr($idcard, 6, ...

  7. Expected indentation of 0 spaces but found 2

    在搭建vue项目时候,启动后就提示 http://eslint.org/docs/rules/indent Expected indentation of 0 spaces but found 2 由 ...

  8. Python爬虫教程-14-爬虫使用filecookiejar保存cookie文件(人人网)

    Python爬虫教程-14-爬虫使用filecookiejar保存cookie文件(人人网) 上一篇介绍了利用CookieJar访问人人网,本篇将使用filecookiejar将cookie以文件形式 ...

  9. sql语句查询一个表里面无重复并且按照指定字段排序的sql语句

    SELECT a.* FROM product_template a INNER JOIN (SELECT p_id,MAX(ID) as max_id FROM product_template w ...

  10. java实现哈弗曼树和哈夫曼树压缩

    本篇博文将介绍什么是哈夫曼树,并且如何在java语言中构建一棵哈夫曼树,怎么利用哈夫曼树实现对文件的压缩和解压.首先,先来了解下什么哈夫曼树. 一.哈夫曼树 哈夫曼树属于二叉树,即树的结点最多拥有2个 ...