GVKun编程网logo

ASP.NET Core Web API 异常处理(asp.net core app failed to start)

7

本文将为您提供关于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)

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项目

.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 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 全局异常中间件

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之异常

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之异常的相关知识,请在本站搜索。

本文标签:

上一篇使用 PowerShell 以管理员身份运行命令?(powershell怎么以管理员身份运行)

下一篇使用 babel 和 webpack 时如何生成 sourcemap?(webpack 中如何配置 babel?)