本文将为您提供关于ASP.NETCoreWebAPI异常处理的详细介绍,我们还将为您解释asp.netcoreappfailedtostart的相关知识,同时,我们还将为您提供关于.NET6-Asp.
本文将为您提供关于ASP.NET Core Web API 异常处理的详细介绍,我们还将为您解释asp.net core app failed to start的相关知识,同时,我们还将为您提供关于.NET6-Asp.Net Core webapi -从零开始的webapi项目、ASP.NET Core 2.2 WebApi 系列【一】搭建ASP.NET Core WebApi项目、Asp.Net Core Web Api 全局异常中间件、asp.net core web api之异常的实用信息。
本文目录一览:- ASP.NET Core Web API 异常处理(asp.net core app failed to start)
- .NET6-Asp.Net Core webapi -从零开始的webapi项目
- ASP.NET Core 2.2 WebApi 系列【一】搭建ASP.NET Core WebApi项目
- Asp.Net Core Web Api 全局异常中间件
- asp.net core web api之异常
ASP.NET Core Web API 异常处理(asp.net core app failed to start)
在使用常规 ASP.NET Web API 多年后,我将 ASP.NET Core 用于我的新 REST API 项目。我没有看到任何处理 ASP.NET
Core Web API 异常的好方法。我试图实现一个异常处理过滤器/属性:
public class ErrorHandlingFilter : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
HandleExceptionAsync(context);
context.ExceptionHandled = true;
}
private static void HandleExceptionAsync(ExceptionContext context)
{
var exception = context.Exception;
if (exception is MyNotFoundException)
SetExceptionResult(context,exception,HttpStatusCode.NotFound);
else if (exception is MyUnauthorizedException)
SetExceptionResult(context,HttpStatusCode.Unauthorized);
else if (exception is MyException)
SetExceptionResult(context,HttpStatusCode.BadRequest);
else
SetExceptionResult(context,HttpStatusCode.InternalServerError);
}
private static void SetExceptionResult(
ExceptionContext context,Exception exception,HttpStatusCode code)
{
context.Result = new JsonResult(new ApiResponse(exception))
{
StatusCode = (int)code
};
}
}
这是我的启动过滤器注册:
services.AddMvc(options =>
{
options.Filters.Add(new AuthorizationFilter());
options.Filters.Add(new ErrorHandlingFilter());
});
我遇到的问题是,当我发生异常时,AuthorizationFilter
它没有被ErrorHandlingFilter
. 我期待它会像使用旧的
ASP.NET Web API 一样被捕获。
那么如何捕获所有应用程序异常以及来自操作过滤器的任何异常?
.NET6-Asp.Net Core webapi -从零开始的webapi项目
本项目为本人22年毕设项目,后续会不断更新本篇文章,全部内容都会写在这一篇文章里,喜欢的请持续关注。
一、如何创建 Asp.Net Core webapi 项目
二、如何使用 EntityFrameWorkCore DbFirst:
需要用到的程序包:
1.数据库创建好表
2.程序包管理器控制台-执行命令
Scaffold-DbContext "server=localhost;port=3306;user=root;password=a.1234;database=lrms;Persist Security Info=True;" Pomelo.EntityFrameworkCore.MysqL -o Models -f
3.执行成功后会在项目下生成你指定的的文件夹(这里是命令中的Models),里面会生成对应的表类和一个连接数据库的上下文类(这里是 “数据库名+Context” )。
ASP.NET Core 2.2 WebApi 系列【一】搭建ASP.NET Core WebApi项目
一、步骤
从“文件”菜单中选择“新建”>“项目” 。
选择“ASP.NET Core Web 应用程序”模板,再单击“下一步” 。
将项目命名为 NetCoreWebApi,然后单击“创建” 。
选择“.NET Core”和“ASP.NET Core 2.2” 。 选择“API”模板,然后单击“创建” 。
创建完成后,项目结构如下:
二、项目解读
Properties——launchSettings.json
启动配置文件,一个ASP.NET Core应用保存特有的配置标准,用于应用的启动准备工作,包括环境变量,开发端口等。
1 {
2 "$schema": "http://json.schemastore.org/launchsettings.json",
3 "iisSettings": { //选择以IIS Express启动
4 "windowsAuthentication": false, //是否启用windows身份验证
5 "anonymousAuthentication": true, //是否启用匿名身份验证
6 "iisExpress": {
7 "applicationUrl": "http://localhost:60953", //IIS Express随机端口
8 "sslPort": 0
9 }
10 },
11 "profiles": {
12 "IIS Express": {
13 "commandName": "IISExpress",
14 "launchBrowser": true, //是否在浏览器中启动
15 "launchUrl": "api/values", //在浏览器中启动的相对URL
16 "environmentVariables": { //将环境变量设置为键/值对
17 "ASPNETCORE_ENVIRONMENT": "Development"
18 }
19 },
20 "NetCoreWebApi": {
21 "commandName": "Project",
22 "launchBrowser": true,
23 "launchUrl": "api/values",
24 "applicationUrl": "http://localhost:5000",
25 "environmentVariables": {
26 "ASPNETCORE_ENVIRONMENT": "Development"
27 }
28 }
29 }
30 }
appsetting.json
appsetting.json是应用程序配置文件,类似于ASP.NET MVC应用程序中的Web.config配置文件。
例如:连接字符串,等等....
1 {
2 "Logging":{
3 "LogLevel":{
4 "Default":"Warning"
5 }
6 },
7 "AllowedHosts":"*",
8 "ConnectionStrings":{
9 "SqlServer":"Data Source=.;Initial Catalog=NetCoreWebApi;User Id=sa;Password=123;"
10 }
11 }
Program.cs
Program.cs文件是应用的入口, 启动后通过UseStartup<Startup>()指定下文的Startup启动文件进行启动。
1 public class Program
2 {
3 public static void Main(string[] args)
4 {
5 CreateWebHostBuilder(args).Build().Run();
6 }
7
8 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
9 WebHost.CreateDefaultBuilder(args)//创建WebHostBuilder。
10 .UseStartup<Startup>();//指定启动类,用于依赖注入和中间件注册。
11 }
Startup.cs
该文件是默认文件,不可随意删除,在此文件中可以以包含服务配置、定义请求处理管道的重要操作。
ConfigureServices 方法用于将服务注入到 IServiceCollection 服务容器中。
Configure方法用于应用响应 HTTP 请求,将中间件注册到 ApplicationBuilder中来配置请求管道。
1 public class Startup
2 {
3 public Startup(IConfiguration configuration)
4 {
5 Configuration = configuration;
6 }
7
8 public IConfiguration Configuration { get; }
9
10 //负责注入服务
11 public void ConfigureServices(IServiceCollection services)
12 {
13 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
14 }
15
16 // 响应 HTTP 请求的方式。可将中间件注册到IApplicationBuilder 实例来配置请求管道。
17 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
18 {
19 if (env.IsDevelopment())
20 {
21 app.UseDeveloperExceptionPage();
22 }
23
24 app.UseMvc();
25 }
26 }
三、测试
此时项目已经完成,按 Ctrl+F5 运行之后,就能看到
这是一个最基础的.NET Core API 环境,离我们想要的API框架还很远,但是其实已经成功一半了,因为好的开始是成功的一半!
Asp.Net Core Web Api 全局异常中间件
中间件处理异常能够获取系统异常
1、添加异常处理中间件AppExceptionHandlerMiddleware
public class AppExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
private AppExceptionHandlerOption _option = new AppExceptionHandlerOption();
private readonly IDictionary<int, string> _exceptionStatusCodeDic;
private readonly ILogger<AppExceptionHandlerMiddleware> _logger;
public AppExceptionHandlerMiddleware(RequestDelegate next, Action<AppExceptionHandlerOption> actionOptions, ILogger<AppExceptionHandlerMiddleware> logger)
{
_next = next;
_logger = logger;
actionOptions(_option);
_exceptionStatusCodeDic = new Dictionary<int, string>
{
{ 401, "未授权的请求" },
{ 404, "找不到该页面" },
{ 403, "访问被拒绝" },
{ 500, "服务器发生意外的错误" }
};
}
public async Task Invoke(HttpContext context)
{
Exception exception = null;
try
{
await _next(context); //调用管道执行下一个中间件
}
catch (AppException ex)
{
context.Response.StatusCode = StatusCodes.Status200OK;
var apiResponse = new ApiResponse(){IsSuccess = false,Message = ex.ErrorMsg};
var serializerResult = JsonConvert.SerializeObject(apiResponse);
context.Response.ContentType = "application/json;charset=utf-8";
await context.Response.WriteAsync(serializerResult);
}
catch (Exception ex)
{
context.Response.Clear();
context.Response.StatusCode = StatusCodes.Status500InternalServerError; //发生未捕获的异常,手动设置状态码
exception = ex;
}
finally
{
if (_exceptionStatusCodeDic.ContainsKey(context.Response.StatusCode) && !context.Items.ContainsKey("ExceptionHandled")) //预处理标记
{
string errorMsg;
if (context.Response.StatusCode == 500 && exception != null)
{
errorMsg = $"{(exception.InnerException != null ? exception.InnerException.Message : exception.Message)}";
_logger.LogError(errorMsg);
}
else
{
errorMsg = _exceptionStatusCodeDic[context.Response.StatusCode];
}
exception = new Exception(errorMsg);
}
if (exception != null)
{
var handleType = _option.HandleType;
if (handleType == AppExceptionHandleType.Both) //根据Url关键字决定异常处理方式
{
var requestPath = context.Request.Path;
handleType = _option.JsonHandleUrlKeys != null && _option.JsonHandleUrlKeys.Count(
k => requestPath.StartsWithSegments(k, StringComparison.CurrentCultureIgnoreCase)) > 0
? AppExceptionHandleType.JsonHandle
: AppExceptionHandleType.PageHandle;
}
if (handleType == AppExceptionHandleType.JsonHandle)
await JsonHandle(context, exception);
else
await PageHandle(context, exception, _option.ErrorHandingPath);
}
}
}
/// <summary>
/// 统一格式响应类
/// </summary>
/// <param name="ex"></param>
/// <returns></returns>
private ApiResponse GetApiResponse(Exception ex)
{
return new ApiResponse() { IsSuccess = false, Message = ex.Message };
}
/// <summary>
/// 处理方式:返回Json格式
/// </summary>
/// <param name="context"></param>
/// <param name="ex"></param>
/// <returns></returns>
private async Task JsonHandle(HttpContext context, System.Exception ex)
{
var apiResponse = GetApiResponse(ex);
var serializerResult = JsonConvert.SerializeObject(apiResponse);
context.Response.ContentType = "application/json;charset=utf-8";
await context.Response.WriteAsync(serializerResult);
}
/// <summary>
/// 处理方式:跳转网页
/// </summary>
/// <param name="context"></param>
/// <param name="ex"></param>
/// <param name="path"></param>
/// <returns></returns>
private async Task PageHandle(HttpContext context, System.Exception ex, PathString path)
{
context.Items.Add("Exception", ex);
var originPath = context.Request.Path;
context.Request.Path = path; //设置请求页面为错误跳转页面
try
{
await _next(context);
}
catch
{
}
finally
{
context.Request.Path = originPath; //恢复原始请求页面
}
}
}
2、添加异常处理配置项 AppExceptionHandlerOption
public class AppExceptionHandlerOption
{
public AppExceptionHandlerOption(
AppExceptionHandleType handleType = AppExceptionHandleType.JsonHandle,
IList<PathString> jsonHandleUrlKeys = null,
string errorHandingPath = "")
{
HandleType = handleType;
JsonHandleUrlKeys = jsonHandleUrlKeys;
ErrorHandingPath = errorHandingPath;
}
/// <summary>
/// 异常处理方式
/// </summary>
public AppExceptionHandleType HandleType { get; set; }
/// <summary>
/// Json处理方式的Url关键字
/// <para>仅HandleType=Both时生效</para>
/// </summary>
public IList<PathString> JsonHandleUrlKeys { get; set; }
/// <summary>
/// 错误跳转页面
/// </summary>
public PathString ErrorHandingPath { get; set; }
}
3、错误处理方案
/// <summary>
/// 错误处理方式
/// </summary>
public enum AppExceptionHandleType
{
JsonHandle = 0, //Json形式处理
PageHandle = 1, //跳转网页处理
Both = 2 //根据Url关键字自动处理
}
4、相应结构
public class ApiResponse
{
public int State => IsSuccess ? 1 : 0;
public bool IsSuccess { get; set; }
public string Message { get; set; }
}
5、扩展
public static class AppExceptionHandlerExtensions
{
public static IApplicationBuilder UserAppExceptionHandler(this IApplicationBuilder app, Action<AppExceptionHandlerOption> options)
{
return app.UseMiddleware<AppExceptionHandlerMiddleware>(options);
}
}
6、自定义异常类型
public class AppException:Exception
{
public string ErrorMsg { get; set; }
public AppException(string errorMsg)
{
ErrorMsg = errorMsg;
}
}
asp.net core web api之异常
官方建议用app.UseExceptionHandler("/error")来集中处理异常,本例是一个具体的应用。
比如项目中有一个ViewModel,要求Name最大长度为5
/// <summary>
/// 用户模型
/// </summary>
public class UserModel
{
/// <summary>
/// ID
/// </summary>
public int ID { get; set; }
/// <summary>
///名称
/// </summary>
[MaxLength(5, ErrorMessage = "长度不能超过5")]
public string Name { get; set; }
}
在TestController中有两个Action,都有异常的机率,Get方法中,一个异常是系统内置的0被整除,另一个是我们自定义的业务层级异常(.NET架构小技巧(8)中有涉及);AddUser是有Model验证有可能Name超过5个字符后报异常。Error方法一个错误处理Action,根据上下文的异常来分流系统内置异常,还是自定业务异常。
/// <summary>
/// get接口
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult Get()
{
var ran = new Random();
switch (ran.Next(1, 4))
{
case 1:
int i = 0;
var j = 10 / i;
return Ok();
case 2:
throw new RegisteredException("这是一个错误");
default:
return Ok();
}
}
/// <summary>
/// 添加用户接口
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
[HttpPost("/adduser")]
public IActionResult AddUser([FromBody] UserModel user)
{
return Ok(user);
}
/// <summary>
/// 错误处理页
/// </summary>
/// <returns></returns>
[HttpGet("/error")]
public IActionResult Error()
{
var context = HttpContext.Features.Get<IExceptionHandlerFeature>();
//如果是业务自定义异常,进行特殊处理
if (context.Error is DaMeiException)
{
return Problem(detail: context.Error.StackTrace, title: $"{context.Error.Message}", type: "HIS");
}
else
{
return Problem(detail: context.Error.StackTrace, title: context.Error.Message);
}
}
层级异常类
using System;
namespace WebApiError
{
/// <summary>
/// 产品异常
/// </summary>
public class DaMeiException : ApplicationException
{
/// <summary>
///
/// </summary>
/// <param name="message"></param>
public DaMeiException(string message) : base(message)
{
}
}
/// <summary>
/// His项目异常
/// </summary>
public class HisException : DaMeiException
{
/// <summary>
///
/// </summary>
/// <param name="message"></param>
public HisException(string message) : base(message)
{
}
}
/// <summary>
/// Lis项目异常
/// </summary>
public class LisException : DaMeiException
{
/// <summary>
///
/// </summary>
/// <param name="message"></param>
public LisException(string message) : base(message)
{
}
}
/// <summary>
/// 模块异常
/// </summary>
public class RegisteredException : HisException
{
/// <summary>
///
/// </summary>
/// <param name="message"></param>
public RegisteredException(string message) : base(message)
{
}
}
}
Error的Action之所有调用到,是因为Configure中添加如下代码,把所有异常交给"/error"来处理。
app.UseExceptionHandler("/error");
添加DaMeiProblemDetailsFactory来兼容各类异常,自定义异常和Model验证异常
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Collections.Generic;
namespace WebApiError
{
/// <summary>
///
/// </summary>
public class DaMeiProblemDetailsFactory : ProblemDetailsFactory
{
/// <summary>
/// 处理业务错误
/// </summary>
/// <param name="httpContext"></param>
/// <param name="statusCode"></param>
/// <param name="title"></param>
/// <param name="type"></param>
/// <param name="detail"></param>
/// <param name="instance"></param>
/// <returns></returns>
public override ProblemDetails CreateProblemDetails(HttpContext httpContext, int? statusCode = null, string title = null, string type = null, string detail = null, string instance = null)
{
var problem = new ProblemDetails()
{
Title = string.IsNullOrEmpty(type) ? title : $"业务异常错误:{title}",
Detail = detail,
Status = statusCode,
Instance = instance,
Type = type
};
return problem;
}
/// <summary>
/// 处理model验证错误
/// </summary>
/// <param name="httpContext"></param>
/// <param name="modelStateDictionary"></param>
/// <param name="statusCode"></param>
/// <param name="title"></param>
/// <param name="type"></param>
/// <param name="detail"></param>
/// <param name="instance"></param>
/// <returns></returns>
public override ValidationProblemDetails CreateValidationProblemDetails(HttpContext httpContext, ModelStateDictionary modelStateDictionary, int? statusCode = null, string title = null, string type = null, string detail = null, string instance = null)
{
var problem = new ValidationProblemDetails()
{
Title = "Model验证错误",
Detail = detail,
Status = statusCode,
Instance = instance,
Type = type
};
foreach (var a in modelStateDictionary)
{
var errorList = new List<string>();
foreach (var error in a.Value.Errors)
{
errorList.Add(error.ErrorMessage);
}
problem.Errors.Add(new KeyValuePair<string, string[]>(a.Key, errorList.ToArray()));
}
return problem;
}
}
}
在ConfigureServices中需要注入DaMeiProblemDetailsFactory
services.AddTransient<ProblemDetailsFactory, DaMeiProblemDetailsFactory>();
其实还可以用Action过滤器来统一管理异常
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace WebApiError
{
/// <summary>
/// 自定义过滤器处理异常
/// </summary>
public class DaMeiExceptionFilter : IActionFilter, IOrderedFilter
{
/// <summary>
///
/// </summary>
public int Order { get; } = int.MaxValue - 10;
/// <summary>
///
/// </summary>
/// <param name="context"></param>
public void OnActionExecuting(ActionExecutingContext context)
{
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
public void OnActionExecuted(ActionExecutedContext context)
{
if (context?.Exception != null)
{
context.Result = new ObjectResult(context.Exception.Message)
{
StatusCode = 500
};
context.ExceptionHandled = true;
}
}
}
}
另外一种方式是通过Action过滤器来处理
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace WebApiError
{
/// <summary>
/// 自定义过滤器处理异常
/// </summary>
public class DaMeiExceptionFilter : IActionFilter, IOrderedFilter
{
/// <summary>
///
/// </summary>
public int Order { get; } = int.MaxValue - 10;
/// <summary>
///
/// </summary>
/// <param name="context"></param>
public void OnActionExecuting(ActionExecutingContext context)
{
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
public void OnActionExecuted(ActionExecutedContext context)
{
if (context?.Exception != null)
{
if (context.Exception is DaMeiException)
{
context.Result = new ObjectResult(context.Exception.Message)
{
Value = $"业务异常:{ context.Exception.Message}",
StatusCode = 500
};
}
else
{
context.Result = new ObjectResult(context.Exception.Message)
{
Value = context.Exception.Message,
StatusCode = 500
};
}
context.ExceptionHandled = true;
}
}
}
}
添加全局过滤器
services.AddControllers(options =>
{
options.Filters.Add(new DaMeiExceptionFilter());
});
本文分享自微信公众号 - dotNET跨平台(opendotnet)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
今天关于ASP.NET Core Web API 异常处理和asp.net core app failed to start的讲解已经结束,谢谢您的阅读,如果想了解更多关于.NET6-Asp.Net Core webapi -从零开始的webapi项目、ASP.NET Core 2.2 WebApi 系列【一】搭建ASP.NET Core WebApi项目、Asp.Net Core Web Api 全局异常中间件、asp.net core web api之异常的相关知识,请在本站搜索。
本文标签: