我是靠谱客的博主 沉默哈密瓜,最近开发中收集的这篇文章主要介绍在 ASP.NET Core 中使用中间件处理异常,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

    • 前言:
    • 一、开发人员异常页
    • 二、异常处理程序页
    • 三、异常处理程序 lambda
    • 四、异常过滤器 IExceptionFilter
        • 1) 直接实现 IExceptionFilter 的方式
        • 2) 继承 ExceptionFilterAttribute 的方式

    • 参考文档

前言:

本文使用 .NET Core SDK 3.1 的版本,介绍了处理 ASP.NET Core Web 应用中常见异常的一些方法。
本文 Demo 中贯穿全文的代码如下:

#region Enums
public enum ResultState
{
请求成功 = 200, 未登录 = 300, 业务错误 = 500, 未知错误 = 999
}
#endregion
#region Exceptions
public interface IKnownException
{
public ResultState Code { get; set; }
public string Message { get; }
public object Result { get; }
}
public class KnownException : Exception, IKnownException
{
public KnownException(string message) : base(message) { }
public KnownException(string message, object result) : base(message) { Result = result; }
public ResultState Code { get; set; }
public object Result { get; }
}
public class KnownExceptionMessage : IKnownException
{
public ResultState Code { get; set; }
public string Message { get; private set; }
public object Result { get; private set; }
public readonly static IKnownException UnKnown = new KnownExceptionMessage { Message = "未知错误", Code = ResultState.未知错误 };
public IKnownException FromKnownException(IKnownException knownException)
{
return new KnownExceptionMessage { Code = knownException.Code, Message = knownException.Message, Result = knownException.Result };
}
}
#endregion

一、开发人员异常页

开发人员异常页 显示请求异常的详细信息。
Startup.Configure 方法添加代码,以当应用在开发环境中运行时启用此页:


if (env.IsDevelopment())
{
// 开发人员异常页
app.UseDeveloperExceptionPage();
}

根据中间件管道的顺序,将 UseDeveloperExceptionPage` 调用置于要捕获其异常的任何中间件前面。
仅当应用程序在开发环境中运行时才启用开发人员异常页 。

二、异常处理程序页

为生产环境配置自定义错误处理页,使用异常处理中间件。
使用 UseExceptionHandler 在非开发环境中添加异常处理中间件:


if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
else
app.UseExceptionHandler("/Error");

异常的 Controller 如下:


[ApiController]
public class ErrorController : ControllerBase
{
private readonly JsonSerializerOptions jsonSerializerOptions;
public ErrorController(IOptionsMonitor<JsonOptions> jsonOptins)
{
jsonSerializerOptions = jsonOptins.CurrentValue.JsonSerializerOptions;
}
[Route("Error")]
[AllowAnonymous]
public async Task Error()
{
var exceptionHandlerPathFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
// var originalRequestPath = exceptionHandlerPathFeature?.Path; // 原始路径
var knownException = exceptionHandlerPathFeature.Error as IKnownException; // 
if (knownException == null)
{
// 未知异常 Http 响应码 500
HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
}
else
{
knownException.Code = ResultState.业务错误;
// 业务逻辑异常 Http 响应码 200 
HttpContext.Response.StatusCode = StatusCodes.Status200OK;
}
HttpContext.Response.ContentType = "application/json;";
await HttpContext.Response.WriteAsync(
JsonSerializer.Serialize(knownException, jsonSerializerOptions), Encoding.UTF8);
}
}

使用 [AllowAnonymous] 允许匿名访问,未身份验证也能够访问。
上面代码使用 IExceptionHandlerPathFeature 访问上下文报出的异常信息和原始路径。
如果我们使用以下代码:


[HttpGet]
public int[] Index()
{
throw new KnownException("this is message", "this is result");
return new int[] { 1, 2, 3 };
}

前端将得到如下JSON:

	{"code":500,"message":"this is message","result":"this is result"}

如果返回值中有中文可能会被转换为 Unicode,请修改 JsonSerializerOptionsEncoder 属性为 JavaScriptEncoder.UnsafeRelaxedJsonEscaping

#region Startup.ConfigureServices
services.AddControllers()
// services.AddMvc()
.AddJsonOptions(jsonOptions =>
{
jsonOptions.JsonSerializerOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
});
#endregion
or
#region
var jsonSerializerOptions = context.RequestServices.GetService<IOptionsMonitor<JsonOptions>>()
.CurrentValue.JsonSerializerOptions;
jsonSerializerOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
#endregion

三、异常处理程序 lambda

异常处理程序页 的替代方法可以向 UseExceptionHandler 提供 lambda,也可以在相应前访问上下文报出的异常。


app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
// var originalRequestPath = exceptionHandlerPathFeature?.Path;
var knownException = exceptionHandlerPathFeature.Error as IKnownException;
if (knownException == null)
{
// 未知异常 Http 响应码 500
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
}
else
{
knownException.Code = ResultState.业务错误;
// 业务逻辑异常 Http 响应码 200 
context.Response.StatusCode = StatusCodes.Status200OK;
}
var jsonSerializerOptions = context.RequestServices.GetService<IOptionsMonitor<JsonOptions>>()
.CurrentValue.JsonSerializerOptions;
context.Response.ContentType = "application/json;";
await context.Response.WriteAsync(
JsonSerializer.Serialize(knownException, jsonSerializerOptions), Encoding.UTF8);
});
});

四、异常过滤器 IExceptionFilter

异常过滤器只作用于 MVC 的生命周期,
如果我们需要对 Controller 进行特殊异常处理,对整体来讲又需要用整体的异常出来,可以用 IExceptionFilter

1) 直接实现 IExceptionFilter 的方式

#region Startup.ConfigureServices
services.AddControllers(mvcOptions =>
{
mvcOptions.Filters.Add<MyExceptionFilter>();
}).AddJsonOptions(jsonOptions =>
{
// 如果返回值中有中文可能会被转换为 Unicode 。
jsonOptions.JsonSerializerOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
});
#endregion
#region MyExceptionFilter
public class MyExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
var knownException = context.Exception as IKnownException;
if (knownException == null)
{
knownException = KnownExceptionMessage.UnKnown;
context.HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
}
else
{
knownException.Code = ResultState.业务错误;
knownException = new KnownExceptionMessage().FromKnownException(knownException);
context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
}
context.Result = new JsonResult(knownException)
{
ContentType = "application/json; charset=utf-8"
};
}
}
#endregion

2) 继承 ExceptionFilterAttribute 的方式

ExceptionFilterAttribute 也实现了 IExceptionFilter接口。
写法和 直接实现 IExceptionFilter 的方式 一样的


public class MyExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
var knownException = context.Exception as IKnownException;
if (knownException == null)
{
knownException = KnownExceptionMessage.UnKnown;
context.HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
}
else
{
knownException.Code = ResultState.业务错误;
knownException = new KnownExceptionMessage().FromKnownException(knownException);
context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
}
context.Result = new JsonResult(knownException)
{
ContentType = "application/json; charset=utf-8"
};
}
}

在使用时,我们可以直接拦截所有的 Controller 的错误:


services.AddControllers(mvcOptions =>
{
mvcOptions.Filters.Add<MyExceptionFilterAttribute>();
});

也可以使用注解的方式单独拦截某个 Controller


[ApiController]
[MyExceptionFilter]
public class HomeController : ControllerBase { /* Do something... */}


参考文档

处理 ASP.NET Core 中的错误

最后

以上就是沉默哈密瓜为你收集整理的在 ASP.NET Core 中使用中间件处理异常的全部内容,希望文章能够帮你解决在 ASP.NET Core 中使用中间件处理异常所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(44)

评论列表共有 0 条评论

立即
投稿
返回
顶部