确保
应用程序的稳定性、可靠性和安全性
。在发生错误或异常情况时,异常处理机制能够捕获
并适当处理这些错误,以防止程序崩溃
,并向用户提供有关错误的反馈。提供有关错误的清晰信息
,而不是简单地崩溃。这有助于用户理解和解决问题
,并提高对应用程序的信任度。开发人员
提供了诊断和调试
应用程序的工具。通过查看异常信息,开发人员可以确定问题的根源,并采取适当的措施来解决它。这有助于减少开发时间和成本,并提高应用程序的质量。异常的抛出、捕获和传播
。在 .NET Core 中,异常通常通过使用 try-catch 块
来捕获。当 try 块
中的代码引发异常
时,控制流将立即转移到相应的 catch 块
中,以便处理异常
。捕获特定类型
的异常或其子类。这使得开发人员
能够根据需要定制异常
处理逻辑,例如只处理特定类型的异常或将其记录到日志
中。调用堆栈传播
的过程。在 .NET Core 中,如果一个方法引发了异常,并且该异常没有被该方法内部的 catch 块捕获
,那么该异常将被传播到调用该方法
的方法中。这个过程将继续进行,直到找到一个 catch 块
来捕获该异常,或者直到该异常到达应用程序
的入口点。.NET 6及更高版本
中,可以使用异常过滤器
来简化异常处理逻辑。异常过滤器是使用ExceptionFilterAttribute
特性标记的类,这些类必须实现IExceptionFilter
接口。通过实现OnException
方法,可以在方法执行期间
捕获异常。异常过滤器
中,可以使用 catch 块
来捕获异常。通过检查异常的类型和信息
,可以决定是否要处理该异常或将其传递给下一个过滤器或控制器
。异常过滤器
应用于ASP.NET Core
应用程序,需要在启动类或配置文件中注册
它们。注册后,它们将自动应用于所有控制器和动作方法
。CustomExceptionFilter
和Program.cs
中注册 相关例子
实现代码: [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CustomExceptionFilter : ExceptionFilterAttribute, IExceptionFilter
{
public override void OnException(ExceptionContext context)
{
// 捕获并处理所有在控制器操作方法执行期间抛出的异常
var exception = context.Exception;
// 这里可以自定义判断异常处理
if (exception is NotImplementedException)
{
// 处理特定类型的异常
context.Result = new JsonResult(new { error = "未实现的功能" });
context.HttpContext.Response.StatusCode = StatusCodes.Status501NotImplemented;
}
else if (context.ModelState.IsValid == false)
{
// 模型验证错误与特定异常结合的情况,可以返回更友好的错误消息
context.Result = new BadRequestObjectResult(context.ModelState);
}
else if (exception is ArgumentNullException)
{
// 参数为null或者为空
context.Result = new JsonResult(new { message = "请求参数无效,请检查后重新提交。" });
}
else
{
// 其他未特别处理的异常,可以选择记录日志,是否应传递给下一个过滤器或控制器
// 这里记录日志
Console.WriteLine($"异常信息:{exception.Message}");
context.ExceptionHandled = true; // 标记该异常已在此处处理
}
base.OnException(context);
}
}
// 注册服务
builder.Services.AddControllers(options =>
{
// 全局应用异常过滤器
options.Filters.Add(typeof(CustomExceptionFilter));
});
IActionFilter、IExceptionFilter 和 IResultFilter
接口,可以创建自定义的过滤器类。这些接口提供了在动作执行之前、之后或发生异常时执行的方法。 IExceptionFilter
接口的类中,可以编写代码来处理异常。当控制器中的动作抛出异常时,该过滤器的 OnException
方法将被调用。自定义过滤器
添加到控制器或动作方法
上,或者通过在全局范围内注册
它们,可以将过滤器应用于ASP.NET Core应用程序的特定部分或所有部分。接口定义过滤器``和
Program.cs中注册 相关
例子`实现相关代码:// 定义实现接口过滤器
public class CustomFilters : Attribute, IActionFilter, IExceptionFilter, IResultFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
//方法执行之前调用
Console.WriteLine($"[CustomFilters] OnActionExecuting: {context.ActionDescriptor.DisplayName}");
}
public void OnActionExecuted(ActionExecutedContext context)
{
//方法执行之后调用
Console.WriteLine($"[CustomFilters] OnActionExecuted: {context.ActionDescriptor.DisplayName}");
}
public void OnException(ExceptionContext context)
{
//方法执行期间发生异常时调用
Console.WriteLine($"[CustomFilters] Exception caught: {context.Exception.Message}");
//自定义判断处理
//比如
if (context.Exception is ArgumentNullException)
{
context.Result = new JsonResult(new { message = "参数不能为空,请检查后重新提交。" })
{
StatusCode = StatusCodes.Status400BadRequest
};
context.ExceptionHandled = true; // 标记异常已处理,后续处理器不再处理该异常
}
}
public void OnResultExecuting(ResultExecutingContext context)
{
// 返回结果执行之前调用
Console.WriteLine($"[CustomFilters] OnResultExecuting: {context.ActionDescriptor.DisplayName}");
}
public void OnResultExecuted(ResultExecutedContext context)
{
// 返回结果执行之后调用
Console.WriteLine($"[CustomFilters] OnResultExecuted: {context.ActionDescriptor.DisplayName}");
}
}
// 启动时注册
// 注册服务
builder.Services.AddControllers(options =>
{
// 注册过滤器
options.Filters.Add();
});
中间件
是ASP.NET Core
应用程序中处理请求和响应
的组件。通过创建自定义中间件
,您可以捕获由请求管道中的其他组件
引发的异常。中间件
可以访问请求和响应对象
,并在处理过程中检查是否有异常发生
。如果有异常,中间件
可以捕获
它们并执行自定义逻辑,例如记录日志或将用户重定向到错误页面。自定义中间件
添加到ASP.NET Core
应用程序,需要在启动类中的Configure
方法中注册
它。注册后,中间件将自动应用于所有请求管道
。自定义中间件
处理异常和Program.cs
中注册 相关`例子:public class CustomExceptionHandlerMiddleware
{
// 定义个请求委托,存储下一个中间件的引用
private readonly RequestDelegate _next;
public CustomExceptionHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
//处理HTTP请求
try
{
//context当前的HTTP请求上下文
await _next(context);
}
catch (Exception ex)
{
// 在这里捕获并处理异常
//可以把异常写入到日志
Console.WriteLine(ex.Message, "An unhandled exception occurred");
// 设置响应状态码
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
// 根据异常类型返回不同的错误信息或视图
if (ex is ArgumentException)
{
await context.Response.WriteAsJsonAsync(new { error = "参数无效" });
}
else
{
await context.Response.WriteAsync("发生内部服务器错误,请稍后重试");
}
}
}
}
//注册中间件
app.UseMiddleware();
NLog
和NLog.Web.AspNetCore
包// Program.cs 中配置
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
try
{
//配置Nlog
builder.Logging.ClearProviders();
builder.Logging.SetMinimumLevel(LogLevel.Trace);
builder.Host.UseNLog();
}
catch (Exception ex)
{
logger.Error(ex, "Stopped program because of exception");
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
LogManager.Shutdown();
}
// nlog 配置文件
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true" internalLogLevel="Info">
<extensions>
<add assembly="NLog.Web.AspNetCore" />
extensions>
<targets>
<target xsi:type="File" name="debug" fileName="./logs/debug-${shortdate}.log" layout="【记录时间】:${longdate}${newline}【日志级别】:${uppercase:${level}}${newline}【请求地址】: ${aspnet-request-url}${newline}【方 法 名】: ${aspnet-mvc-action}${newline}【日志信息】:${message}${newline}${exception:format=tostring}${newline}" />
<target xsi:type="File" name="info" fileName="./logs/info-${shortdate}.log" layout="【记录时间】:${longdate}${newline}【日志级别】:${uppercase:${level}}${newline}【请求地址】: ${aspnet-request-url}${newline}【方 法 名】: ${aspnet-mvc-action}${newline}【日志信息】:${message}${newline}${exception:format=tostring}${newline}" />
<target xsi:type="File" name="warn" fileName="./logs/warn-${shortdate}.log" layout="【记录时间】:${longdate}${newline}【日志级别】:${uppercase:${level}}${newline}【请求地址】: ${aspnet-request-url}${newline}【方 法 名】: ${aspnet-mvc-action}${newline}【日志信息】:${message}${newline}${exception:format=tostring}${newline}" />
<target xsi:type="File" name="error" fileName="./logs/error-${shortdate}.log" layout="【记录时间】:${longdate}${newline}【日志级别】:${uppercase:${level}}${newline}【请求地址】: ${aspnet-request-url}${newline}【方 法 名】: ${aspnet-mvc-action}${newline}【日志信息】:${message}${newline}${exception:format=tostring}${newline}" />
<target xsi:type="File" name="task" fileName="./logs/task-${shortdate}.log" layout="【记录时间】:${longdate}${newline}【日志级别】:${uppercase:${level}}${newline}【请求地址】: ${aspnet-request-url}${newline}【方 法 名】: ${aspnet-mvc-action}${newline}【日志信息】:${message}${newline}${exception:format=tostring}${newline}" />
<target xsi:type="Console" name="console" layout="${message}" />
targets>
<rules>
<logger name="*" levels="Warn" writeTo="warn" />
<logger name="*" minlevel="Error" maxlevel="Fatal" writeTo="error" />
<logger name="Microsoft.*" maxlevel="Info" final="true" />
rules>
nlog>
异常类来封装
特定的错误信息或状态,并为它们编写相应的处理逻辑。这可以通过创建派生自内置异常类
的自定义异常类来实现。入口点
(例如主函数或程序启动类)中添加代码
来捕获并处理自定义异常。这可以在全局范围内
处理特定类型的异常,以确保它们得到适当的处理和响应。自定义异常类
和全局处理类
以及启动时候注册
相关代码例子// 继承Exception自定义类
public class CustomException : Exception
{
public CustomException(string message) : base(message) { }
}
// 创建一个全局异常处理类
public class GlobalExceptionHandler
{
public static void RegisterGlobalExceptionHandler()
{
// 注册全局异常处理程序
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// 处理异常逻辑
var exception = e.ExceptionObject as CustomException;
if (exception != null)
{
// 处理自定义异常的逻辑
//这里可以返回相关提示给前端
}
else
{
// 处理其他异常的逻辑
//这里可以处理,写入相关日志
}
}
}
//最后在Program.cs中注册自定义异常处理类
// 注册全局异常处理程序
GlobalExceptionHandler.RegisterGlobalExceptionHandler();
公众号“点滴分享技术猿”