Next comes the way of using the proxy method, which means that the ErrorController the whole logic defined directly in the place of registration, use an anonymous delegate to handle the logic and the logic here is the same as before the
app.UseExceptionHandler(errApp =>
{
errApp.Run(async context =>
{
// 在 Features 里面获取异常
var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
// 识别异常是否为 IKnownException
IKnownException knownException = exceptionHandlerPathFeature.Error as IKnownException;
if (knownException == null)
{
// 如果不是则记录并且把错误的响应码响应成 Http 500
var logger = context.RequestServices.GetService<ILogger<MyExceptionFilterAttribute>>();
logger.LogError(exceptionHandlerPathFeature.Error, exceptionHandlerPathFeature.Error.Message);
knownException = KnownException.Unknown;
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
}
else
{
// 如果捕获到的是一个业务逻辑的异常,Http 响应码应该给是 200
knownException = KnownException.FromKnownException(knownException);
context.Response.StatusCode = StatusCodes.Status200OK;
}
// 然后再把响应信息通过 json 的方式输出出去
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));
});
});
For unknown why the exception is to be output Http 500, and for the business logic exceptions, the proposed output Http 200?
Because the monitoring system will actually Http response code identification, when the monitoring system to identify the proportion of 500 Http response is relatively high, the availability of the system will think there is a problem, this time warning system will warn
For this normal identify known business logic, then, to deal with the normal 200 Http is a normal behavior, so you can make the system work better monitor and correct identified some unknown system error messages, false alarms, so that the alarm system is more sensitive, but also to avoid the business logic exception interference warning system
Next, look at the third, by way of exception filter
This is actually a way of action, it is not, it is the role of the entire system occurs in the following frame of MVC earliest occurrence of the role of middleware in the MVC in which the entire life cycle, which means it can only work in request cycle MVC Web API inside
First, a custom MyExceptionFilter
namespace ExceptionDemo.Exceptions
{
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"
};
}
}
}
Processing logic is the same as the previous
Then Registration Filters
services.AddMvc(mvcOptions =>
{
mvcOptions.Filters.Add<MyExceptionFilter>();
}).AddJsonOptions(jsonoptions =>
{
jsonoptions.JsonSerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
});
Start the program, the output is as follows:
{"message":"未知错误","errorCode":9999,"errorData":null}
Consistent with previous output, because it is inside the Controller output error
If the output errors before MVC middleware, then it is no way to deal with the
Under normal circumstances this scenario implies the need for special exception handling Controller, but in terms of overall middleware then have to be treated with another specific logic, you can handle a manner ExceptionFilter
This way you can also by way of Attribute
Customizing a MyExceptionFilterAttribute
namespace ExceptionDemo.Exceptions
{
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"
};
}
}
}
In the Controller marked above MyExceptionFilter
[MyExceptionFilter]
public class WeatherForecastController : ControllerBase
After you start running the same effect
The effect of these two methods are equivalent, except that you can say more fine-grained control of exception handling, may Controller or a designated portion of the Exception to determine our exception handling, or globally registered in ExceptionFilter
Of course, because ExceptionFilterAttribute also achieved IExceptionFilter, so it can also sign up to a global, you can also use it as a global exception handler filters to use, Controller of the above will not require labeling
Registration Filters
services.AddMvc(mvcOptions =>
{
//mvcOptions.Filters.Add<MyExceptionFilter>();
mvcOptions.Filters.Add<MyExceptionFilterAttribute>();
}).AddJsonOptions(jsonoptions =>
{
jsonoptions.JsonSerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
});
Cancel the above label MyExceptionFilter in Controller
//[MyExceptionFilter]
public class WeatherForecastController : ControllerBase
Start the program, consistent output
For this scenario we define some of the API, and the API defined exception handling our convention is helpful
in conclusion
First we need to define the specific exception class or interface, we can define an abstract class, interface means may be used, the example shows, by way of exception business logic interface
For business logic exception, in fact, we need to define a global error code
For unknown anomaly, the output should be a specific output and error code, and then record the complete log, we should not take some of the internal systems such as exception stack information output to the user
For known business logic exception with the way Http 200, for an unknown anomaly, by the way Http 500, which would allow the monitoring system to work better
Another suggestion is to try to record all the details of the exception to the log for subsequent analysis, but also for the surveillance system to do some specific monitoring warning
This work is Creative Commons Attribution - NonCommercial - ShareAlike 4.0 International License Agreement for licensing.
Welcome to reprint, use, repost, but be sure to keep the article signed by Zheng Ziming (containing links: http://www.cnblogs.com/MingsonZheng/), shall not be used for commercial purposes, be sure to publish the same work based on the paper license modification .
If you have any questions, please contact me ([email protected]).