zoukankan      html  css  js  c++  java
  • 重新整理 .net core 实践篇—————异常中间件[二十]

    前言

    简单介绍一下异常中间件的使用。

    正文

    if (env.IsDevelopment())
    {
    	app.UseDeveloperExceptionPage();
    }
    

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

    public static IApplicationBuilder UseDeveloperExceptionPage(this IApplicationBuilder app)
    {
    	if (app == null)
    	{
    		throw new ArgumentNullException(nameof(app));
    	}
    
    	return app.UseMiddleware<DeveloperExceptionPageMiddleware>();
    }
    

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

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

    里面的invoke:

    public async Task Invoke(HttpContext context)
    {
    	try
    	{
    		await _next(context);
    	}
    	catch (Exception ex)
    	{
    	    // 异常处理
    	}
    }
    

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

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

    测试:

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

    结果:

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

    正式环境:

    app.UseExceptionHandler("/error");
    

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

    [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);
    	}
    }
    

    视图:

    <html>
    <head>
    
    </head>
    <body>
    <div>
        错误码: @Model.ErrorCode
    </div>
    <div>
        错误信息: @Model.Message
    </div>
    </body>
    </html>
    

    IKnownException:

    public interface IKnownException
    {
    	public string Message { get; }
    
    	public int ErrorCode { get; }
    
    	public object[] ErrorData { get; }
    }
    

    KnownException:

    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:

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

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

    现在弄一个支付异常:

    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:

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

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

    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中生效,而不是全局生效:

    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 中注册:

    services.AddMvc(mvcOptions =>
    {
    	mvcOptions.Filters.Add<MyExceptionFilter>();
    }).AddJsonOptions(jsonOptions =>
    {
    	jsonOptions.JsonSerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
    });
    

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

    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头部:

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

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

    以上只是个人整理,如有错误,望请指点。

    下一节,静态文件,以前写过,重新整理一下。

  • 相关阅读:
    树莓派4B踩坑指南
    树莓派4B踩坑指南
    树莓派4B踩坑指南
    从java反射到注解再到动态代理,一锅端!
    Lc_551学生出勤记录I
    aop日志测试类
    转载-使用@Async异步注解导致该Bean在循环依赖时启动报BeanCurrentlyInCreationException异常的根本原因分析,以及提供解决方案【享学Spring】
    linux 启动和停止脚本
    mysql 2003
    项目启动连不上mysql, Communications link failure
  • 原文地址:https://www.cnblogs.com/aoximin/p/14879712.html
Copyright © 2011-2022 走看看