异常处理方面依照输出返回的内容分为WebMvc/WebApi两种异常处理, WebMvc对应Html页面, WebApi对应Json + Envelop的数据包封装
相关注意事项
- 每个请求最终都会对应到一个Action来处理, 这点类似于之前的HttpHandler, 每个请求最终都是有Handler处理完成的, 这点又体现在 Response的输出上, 可以通过 HttpContext.Response.HasStarted来判断
- 下面注册部分的代码, 我们增加了一个AutoCommiter, 意在所有Action完成之后自动做一次Commit, 避免每个Action内部做Commit, 鉴于第一点的原因, 这个必须加载最里面, 并且这个不能放在Middleware中处理(之前就是放在Middleware中处理的, 后面出现问题才转移到这里),
- 进一步说明: AutoCommiter如果写在Middleware中, 出现提交异常后,我们期望通过Reponse直接输出流, 发现没法写出去, 提示 Response流已经启动了, 这一点是符合上述第一条的判断的, 所以这个AutoCommiter必须移动到ActionFilters中来处理
Action异常的处理方式
Action异常并不采用Try Cache的形式, 异常处理的ActionFilter接口是IExceptionFilter, 而在Action中直接抛出的异常, 并没办法通过TryCache在IActionFilter/IAsyncActionFilter中获取, 而是需要通过ActionExecutedContext.Exception来获取, 可见Action处理过程中如果有异常发生, 会同通过 TryCache拿到异常之后放到ExecutedContext.Exception中, 因此我们上面的AutoCommiter在出现异常之后, 也需要把Exception放到该属性中, 不可直接抛出
public class AutoCommiterFilterAttribute : ActionFilterAttribute, IActionFilter, IAsyncActionFilter, IResultFilter
{
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext.Exception != null) //如果有Exception发生,直接跳过处理
{
return;
}
try
{
var dbContextCommiter = actionExecutedContext.HttpContext.RequestServices.GetService<IDbContextCommiter>();
if (dbContextCommiter != null && dbContextCommiter.IsDbContextCreated)
{
dbContextCommiter.CommitAsync().GetAwaiter().GetResult();
}
}
catch (Exception ex)
{
actionExecutedContext.Exception = ex;
}
}
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var result = await next();
if (result.Exception != null) //如果有Exception发生,直接跳过处理
{
return;
}
try
{
var dbContextCommiter = context.HttpContext.RequestServices.GetService<IDbContextCommiter>();
if (dbContextCommiter != null && dbContextCommiter.IsDbContextCreated)
{
await dbContextCommiter.CommitAsync();
}
}
catch (Exception ex)
{
result.Exception = ex;
}
}
}
WebApi异常处理
框架只提供相关类库, 并不做异常处理的自动注册, 需要再业务系统中自己完成相关注册
注册
整体的注册必须严格按照下面的顺序,
-
作为参与业务处理的AutoCommiterFilter要放到离业务代码最近的地方
-
做封包业务的EnvelopFilter放在所有业务代码处理完成的地方
-
做异常拦截处理的ExceptionHandler, 放到最外层, 负责为Action处理阶段的异常进行兜底
public void ConfigureMvcOptions(MvcOptions mvcOptions, AppBuildContext appBuildContext) { mvcOptions.Filters.Add(); mvcOptions.Filters.Add(); mvcOptions.Filters.Add(); }
WebMVC异常处理
做的不多, 暂不涉及, 后续遇到再补充