前言
在程序设计中,咱们会遇到各种各样的异样问题,一个异样解决不仅仅能够帮忙开发者疾速的定位问题,也能够给用户更好的应用体验,那么咱们在 AspNetCore 我的项目中如何捕捉以及解决异样呢?
而对应 AspNetCore 程序,咱们有两种异样解决计划,它们别离是:
- 异样中间件
- 异样过滤器
介绍
Masa Framework
作为一个框架,它为开发者以及用户提供更好的开发体验和应用体验的异样解决性能
Masa.Utils.Exceptions
中定义了两种异样类
UserFriendlyException
(敌对异样)MasaException
(框架异样)
并提供了两种异样解决计划,那接下来就让咱们看看它们是如何应用的
- 异样中间件
- 异样过滤器
依据须要自行抉择一种计划应用即可
疾速入门
我的项目基于.NET6.0 创立,必须装置所必须的环境
- 装置.NET 6.0
异样中间件
基于中间件实现的全局异样解决,用于捕获应用程序异样,并将异样信息处理后返回
- 新建 ASP.NETCore 空我的项目
Assignment.GlobalExceptionDemo
,并装置Masa.Utils.Exceptions
dotnet new web -o Assignment.GlobalExceptionDemo
cd Assignment.GlobalExceptionDemo
dotnet add package Masa.Utils.Exceptions --version 0.6.0-rc.3 // 提供全局异样过滤器
- 新建用户类
User
public class User
{public string Name { get; set;}
public int Age {get; set;}
}
- 应用全局异样,批改
Program
// 反对解决自定义异样
app.UseMasaExceptionHandler(options =>
{
// 反对解决自定义异样
options.ExceptionHandler = context =>
{if (context.Exception is ArgumentNullException ex)
{context.ToResult($"{ex.ParamName}不能为空");
}
};
});
- 新增注册用户办法(用于自定义抛出异样)
app.MapPost("/register", (User user) =>
{if (string.IsNullOrEmpty(user.Name))
throw new ArgumentNullException(nameof(user.Name));
//todo: Impersonate a registered user
});
更多应用技巧可查看
异样过滤器
基于 MVC 的全局异样过滤器,用于捕获应用程序异样,并将异样信息处理后返回
- 新建 ASP.NET Core 空我的项目
Assignment.GlobalFilterDemo
,并装置Masa.Utils.Exceptions
dotnet new web -o Assignment.GlobalFilterDemo
cd Assignment.GlobalFilterDemo
dotnet add package Masa.Utils.Exceptions --version 0.6.0-rc.3 // 提供全局异样过滤器
- 新建用户类
User
public class User
{public string Name { get; set;}
public int Age {get; set;}
}
- 应用全局异样过滤器,批改
Program
builder.Services
.AddMvc()
// 应用 MasaException
.AddMasaExceptionHandler(options =>
{
options.ExceptionHandler = context =>
{if (context.Exception is ValidationException ex)
{string message = ex.Errors.Select(error => error.ErrorMessage).FirstOrDefault()!;
context.ToResult(message);
}
};
});
- 新增注册用户办法,用于自定义抛出异样
[ApiController]
[Route("[Action]")]
public class UserController : ControllerBase
{[HttpPost]
public void Register(User user)
{if (string.IsNullOrEmpty(user.Name))
throw new ArgumentNullException(nameof(user.Name));
//todo: Impersonate a registered user
}
}
那咱们如何确定异样曾经解决实现了呢?这就须要通过以下这个步骤
验证全局异样解决
别离启用应用异样中间件的我的项目以及异样过滤器的我的项目,用 Postman 或者通过 Swagger 别离申请两个我的项目的注册用户接口,其中 Name
为空,可失去以下提醒,则代表全局异样解决胜利
以上是常规化的异样解决形式,如果遇到自定义异样咱们该如何解决?
让咱们接着往下看
进阶
不论是通过中间件还是过滤器来解决全局异样,咱们都反对自定义异样解决,咱们首先来看一下异样的解决流程
依据流程图能够直观的理解到,只有应用了 Masa
提供的异样解决,哪怕咱们不自定义异样,框架也会帮忙咱们依照无自定义异样流程默认解决异样信息,但如果咱们心愿对特定的异样做出特定的响应,那么就须要咱们自定义异样
自定义异样
自定义异样反对三种形式
以中间件为例:
计划一. 通过配置ExceptionHandler
(异样解决),批改Program.cs
app.UseMasaExceptionHandler(options =>
{
options.ExceptionHandler = context =>
{// 依据 context.Exception 判断异样类型,并通过 context.ToResult()输入响应内容
if (context.Exception is ArgumentNullException ex)
{context.ToResult($"{ex.ParamName}不能为空");
}
};
});
计划二. 通过自定义 ExceptionHandler,并注册到服务汇合
- 自定义异样解决类
ExceptionHandler
,并继承IMasaExceptionHandler
/// <summary>
/// 结构函数参数需反对从 IOC 获取
/// </summary>
public class ExceptionHandler : IMasaExceptionHandler
{public void OnException(MasaExceptionContext context)
{if (context.Exception is ArgumentNullException ex)
{context.ToResult($"{ex.ParamName}不能为空");
}
}
}
- 应用指定的异样 Handler,批改
Program.cs
builder.Services.AddSingleton<IMasaExceptionHandler, ExceptionHandler>();// 注册自定义异样
var app = builder.Build();
app.UseMasaExceptionHandler();// 在 Program 中执行异样处理程序
计划三. 通过自定义 ExceptionHandler 并指定 ExceptionHandler 来实现
- 自定义异样解决类
ExceptionHandler
,并继承IMasaExceptionHandler
/// <summary>
/// 结构函数参数需反对从 IOC 获取
/// </summary>
public class ExceptionHandler : IMasaExceptionHandler
{public void OnException(MasaExceptionContext context)
{if (context.Exception is ArgumentNullException ex)
{context.ToResult($"{ex.ParamName}不能为空");
}
}
}
- 应用指定的异样 Handler,批改
Program.cs
app.UseMasaExceptionHandler(options => options.UseExceptionHanlder<ExceptionHandler>());// 指定应用特定的异样处理程序
上述三种计划任选其一即可,提供的性能时一样的,仅仅是写法不同
批改 HttpStatusCode 状态码
MasaExceptionContext
默认提供了 ToResult
办法反对输出响应内容,状态码(默认: 299),内容类型 (默认:text/plain; charset=utf-8),咱们能够依据本人的理论状况调用传参即可
批改日志级别
异样类型为 UserFriendlyException
的默认日志等级为Information
,其余异样的日志等级为Error
,那么如果我想批改对应异样的日志等级应该怎么做?
配置异样日志关系:
builder.Services.Configure<MasaExceptionLogRelationOptions>(options =>
{options.MapLogLevel<ArgumentNullException>(LogLevel.None);
});
依照此形式,能够将类型为 ArgumentNullException 异样的日志等级设置为 None(不记录日志)
常见问题
Q1: 为什么应用全局异样后没有记录日志?
A1:
- 查看是否指定了自定义异样解决的 Handler,并且以后异样曾经被自定义异样处理程序解决(ExceptionHandled = true)
- 查看以后异样类型是否配置了指定的日志等级,且以后日志等级小于默认记录日志的等级
Q2: 实现 IMasaExceptionHandler
后,为什么产生异样后没有进入OnException
A2: 未注入到服务汇合且没有指定应用指定的 ExceptionHanlder
- 自定义异样 Handler
public class ExceptionHandler : IMasaExceptionHandler
{public void OnException(MasaExceptionContext context)
{throw new NotImplementedException();
}
}
可参考自定义异样中的计划二或者计划三批改即可
总结
Masa 提供的全局异样中间件,对自定义异样的扩大反对较好,并且后续 Masa Framework
反对 I18n 后,全局异样也将减少 I18n 反对, 届时全局异样会更加不便
本章源码
Assignment13
https://github.com/zhenlei520/MasaFramework.Practice
开源地址
MASA.Framework:https://github.com/masastack/MASA.Framework
如果你对咱们的 MASA Framework 感兴趣,无论是代码奉献、应用、提 Issue,欢送分割咱们
- WeChat:MasaStackTechOps
- QQ:7424099