概述
目录
- 前言:
- 一、开发人员异常页
- 二、异常处理程序页
- 三、异常处理程序 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,请修改 JsonSerializerOptions
的 Encoder
属性为 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 中使用中间件处理异常所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复