首页 > 编程语言 > .net core异常中间件的使用
2021
09-04

.net core异常中间件的使用

正文

1
2
3
4
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

这样写入中间件哈,那么在env环境下就会去执行UseDeveloperExceptionPage。

1
2
3
4
5
6
7
8
9
public static IApplicationBuilder UseDeveloperExceptionPage(this IApplicationBuilder app)
{
    if (app == null)
    {
        throw new ArgumentNullException(nameof(app));
    }
 
    return app.UseMiddleware<DeveloperExceptionPageMiddleware>();
}

那么我们应该去看DeveloperExceptionPageMiddleware中间件哈。

那么这里介绍它是如何能够捕获其他中间件的异常的哈。

里面的invoke:

其实它的操作是很简单的,直接在外面套了try catch。

里面的异常处理怎么处理的可以直接去看DeveloperExceptionPageMiddleware 中间件,里面的操作也比较简单处理。

测试:

1
2
3
4
5
6
[HttpGet]
public int GetService([FromServices]ISelfService selfService)
{
    throw new System.Exception("错误");
    return 1;
}

结果:

因为上面说了,这个是dev环境下,那么生产环境不能直接给用户看到错误信息。

正式环境:

1
app.UseExceptionHandler("/error");

将错误转移到/error 处理。具体UseExceptionHandler细节篇里面介绍,有许多可以借鉴的地方。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[ApiController]
[Route("[controller]")]
public class ErrorController : Controller
{
    public ILogger<ErrorController> _logger;
    public ErrorController(ILogger<ErrorController> logger)
    {
        this._logger = logger;
    }
 
    public IActionResult Index()
    {
        var exceptionHandlerPathFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
 
        var ex = exceptionHandlerPathFeature?.Error;
 
        var knownException = ex as IKnownException;
 
        if (knownException == null)
        {
            _logger.LogError(ex, ex.Message);
            knownException = KnownException.Unknow;
        }
        else
        {
            knownException = KnownException.FromKnowException(knowException);
        }
 
        return View(knownException);
    }
}

视图:

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<head>
 
</head>
<body>
<div>
    错误码: @Model.ErrorCode
</div>
<div>
    错误信息: @Model.Message
</div>
</body>
</html>

IKnownException:

1
2
3
4
5
6
7
8
public interface IKnownException
{
    public string Message { get; }
 
    public int ErrorCode { get; }
 
    public object[] ErrorData { get; }
}

KnownException:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class KnownException : IKnownException
{
    public string Message
    {
        get; private set;
    }
 
    public int ErrorCode
    {
        get; private set;
    }
 
    public object[] ErrorData
    {
        get;
        private set;
    }
 
    public readonly static IKnownException Unknow = new KnownException { Message = "未知错误", ErrorCode = 99 };
 
    public static IKnownException FromKnowException(IKnownException Exception)
    {
        return new KnownException{Message = Exception.Message, ErrorCode = Exception.ErrorCode, ErrorData = Exception.ErrorData};
    }
}

测试1:

1
2
3
4
5
6
[HttpGet]
public int GetService([FromServices]ISelfService selfService)
{
    throw new System.Exception("错误");
    return 1;
}

这种属于未知异常,结果:

现在弄一个支付异常:

1
2
3
4
5
6
7
8
9
10
11
12
public class PayErrorException : Exception, IKnownException
{
    public PayErrorException(string message, int errorCode, params object[] errorData): base(message)
    {
        this.ErrorCode = errorCode;
        this.ErrorData = errorData;
    }
 
    public int ErrorCode { get;private set; }
 
    public object[] ErrorData { get;private set; }
}

测试2:

1
2
3
4
5
6
7
[HttpGet]
public int GetService([FromServices]ISelfService selfService)
{
 
    throw new PayErrorException("支付错误",405,null);
    return 1;
}

将异常处理放入到中间件分支中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
app.UseExceptionHandler(errApp =>
{
    errApp.Run(async context =>
    {
        var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
        IKnownException knownException = exceptionHandlerPathFeature.Error as IKnownException;
        if (knownException == null)
        {
            var logger = context.RequestServices.GetService<ILogger<MyExceptionFilterAttribute>>();
            logger.LogError(exceptionHandlerPathFeature.Error, exceptionHandlerPathFeature.Error.Message);
            knownException = KnownException.Unknown;
            context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        }
        else
        {
            knownException = KnownException.FromKnownException(knownException);
            context.Response.StatusCode = StatusCodes.Status200OK;
        }
        var jsonOptions = context.RequestServices.GetService<IOptions<JsonOptions>>();
        context.Response.ContentType = "application/json; charset=utf-8";
        await context.Response.WriteAsync(System.Text.Json.JsonSerializer.Serialize(knownException, jsonOptions.Value.JsonSerializerOptions));
    });
});

效果一样就不演示了。如果是已知异常错误码应该为200,一个是500异常是系统无法处理,系统错误,但是已知错误是属于系统正常处理。另一个是监控系统,认为报500错误,是会持续放出系统警告。

还有一种局部异常,只在mvc中生效,而不是全局生效:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        IKnownException knownException = context.Exception as IKnownException;
        if (knownException == null)
        {
            var logger = context.HttpContext.RequestServices.GetService<ILogger<MyExceptionFilterAttribute>>();
            logger.LogError(context.Exception, context.Exception.Message);
            knownException = KnownException.Unknown;
            context.HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
        }
        else
        {
            knownException = KnownException.FromKnownException(knownException);
            context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
        }
        context.Result = new JsonResult(knownException)
        {
            ContentType = "application/json; charset=utf-8"
        };
    }
}

在mvc 中注册:

1
2
3
4
5
6
7
services.AddMvc(mvcOptions =>
{
    mvcOptions.Filters.Add<MyExceptionFilter>();
}).AddJsonOptions(jsonOptions =>
{
    jsonOptions.JsonSerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
});

最后介绍一种,只作用于某个控制器,或者action:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        IKnownException knownException = context.Exception as IKnownException;
        if (knownException == null)
        {
            var logger = context.HttpContext.RequestServices.GetService<ILogger<MyExceptionFilterAttribute>>();
            logger.LogError(context.Exception, context.Exception.Message);
            knownException = KnownException.Unknown;
            context.HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
        }
        else
        {
            knownException = KnownException.FromKnownException(knownException);
            context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
        }
        context.Result = new JsonResult(knownException)
        {
            ContentType = "application/json; charset=utf-8"
        };
    }
}

查看一下ExceptionFilterAttribute头部:

1
2
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public abstract class ExceptionFilterAttribute : Attribute, IAsyncExceptionFilter, IExceptionFilter, IOrderedFilter

上面标志了可以放于类上也可以放于方法上。所以可以放至在controller上,也可以action上,看需求了。


以上就是.net core异常中间件的使用的详细内容,更多关于.net core异常中间件的资料请关注自学编程网其它相关文章!

编程技巧