- abp在AbpAspNetCoreMvcModule里添加AbpExceptionFilter过滤器的,异常管理主要通过AbpExceptionFilter实现
public class AbpAspNetCoreMvcModule : AbpModule
{
//......省略若干代码
Configure(mvcOptions =>
{
mvcOptions.AddAbp(context.Services);
});
//......
}
public static void AddAbp(this MvcOptions options, IServiceCollection services)
{
//...
AddActionFilters(options);
//...
}
private static void AddActionFilters(MvcOptions options)
{
// ...
// 异常过滤器
options.Filters.AddService(typeof(AbpExceptionFilter));
}
- AbpExceptionFilter过滤器在AbpAspNetCoreMvcModule里添加的,可以直接用,也可以自己添加过滤器重写AbpExceptionFilter自定义Exception类型与返回result
public class MyExceptionFilter : AbpExceptionFilter, ITransientDependency
{
public MyExceptionFilter(IExceptionToErrorInfoConverter errorInfoConverter, IHttpExceptionStatusCodeFinder statusCodeFinder, Volo.Abp.Json.IJsonSerializer jsonSerializer, IOptions exceptionHandlingOptions) : base(errorInfoConverter, statusCodeFinder, jsonSerializer, exceptionHandlingOptions)
{
}
///
/// 是否需要进入异常处理
///
///
///
protected override bool ShouldHandleException(ExceptionContext context)
{
//TODO: Create DontWrap attribute to control wrapping..?
if (context.ActionDescriptor.IsControllerAction() &&
context.ActionDescriptor.HasObjectResult())
{
return true;
}
if (context.HttpContext.Request.CanAccept(MimeTypes.Application.Json))
{
return true;
}
if (context.HttpContext.Request.IsAjax())
{
return true;
}
return false;
}
///
/// 异常处理
///
///
///
protected override async Task HandleAndWrapException(ExceptionContext context)
{
//TODO: Trigger an AbpExceptionHandled event or something like that.
//定义Headers
context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
//定义状态码 可以新增Exception类型,重写IHttpExceptionStatusCodeFinder获取返回StatusCode
context.HttpContext.Response.StatusCode = (int)context
.HttpContext.RequestServices.GetRequiredService()
.GetStatusCode(context.HttpContext, context.Exception);
//获取返回result对象,可以重写自定义返回result
var exceptionHandlingOptions = context.HttpContext.RequestServices.GetRequiredService>().Value;
var exceptionToErrorInfoConverter = context.HttpContext.RequestServices.GetRequiredService();
var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients);
context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo));
//打印日志
var logLevel = context.Exception.GetLogLevel();
var remoteServiceErrorInfoBuilder = new StringBuilder();
remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------");
//remoteServiceErrorInfoBuilder.AppendLine(remoteServiceErrorInfo);
var logger = context.HttpContext.RequestServices.GetService>();
logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString());
logger.LogException(context.Exception, logLevel);
//await context.HttpContext.RequestServices.GetRequiredService().NotifyAsync(new ExceptionNotificationContext(context.Exception));
context.Exception = null; //Handled!
}
}
- 可以按BusinessException格式新增异常类型
[Serializable]
public class BusinessException : Exception,
IBusinessException,
IHasErrorCode,
IHasErrorDetails,
IHasLogLevel
{
public string Code { get; set; }
public string Details { get; set; }
public LogLevel LogLevel { get; set; }
public BusinessException(
string code = null,
string message = null,
string details = null,
Exception innerException = null,
LogLevel logLevel = LogLevel.Warning)
: base(message, innerException)
{
Code = code;
Details = details;
LogLevel = logLevel;
}
///
/// Constructor for serializing.
///
public BusinessException(SerializationInfo serializationInfo, StreamingContext context)
: base(serializationInfo, context)
{
}
public BusinessException WithData(string name, object value)
{
Data[name] = value;
return this;
}
}
- 重写IHttpExceptionStatusCodeFinder接口定义返回StatusCode
public virtual HttpStatusCode GetStatusCode(HttpContext httpContext, Exception exception)
{
if (exception is IHasHttpStatusCode exceptionWithHttpStatusCode &&
exceptionWithHttpStatusCode.HttpStatusCode > 0)
{
return (HttpStatusCode) exceptionWithHttpStatusCode.HttpStatusCode;
}
if (exception is IHasErrorCode exceptionWithErrorCode &&
!exceptionWithErrorCode.Code.IsNullOrWhiteSpace())
{
if (Options.ErrorCodeToHttpStatusCodeMappings.TryGetValue(exceptionWithErrorCode.Code, out var status))
{
return status;
}
}
if (exception is AbpAuthorizationException)
{
return httpContext.User.Identity.IsAuthenticated
? HttpStatusCode.Forbidden
: HttpStatusCode.Unauthorized;
}
//TODO: Handle SecurityException..?
if (exception is AbpValidationException)
{
return HttpStatusCode.BadRequest;
}
if (exception is EntityNotFoundException)
{
return HttpStatusCode.NotFound;
}
if (exception is NotImplementedException)
{
return HttpStatusCode.NotImplemented;
}
if (exception is IBusinessException)
{
return HttpStatusCode.Forbidden;
}
return HttpStatusCode.InternalServerError;
}
- 重写IExceptionToErrorInfoConverter接口定义返回result
public class DefaultExceptionToErrorInfoConverter : IExceptionToErrorInfoConverter, ITransientDependency
{
///....
public RemoteServiceErrorInfo Convert(Exception exception, bool includeSensitiveDetails)
{
var errorInfo = CreateErrorInfoWithoutCode(exception, includeSensitiveDetails);
if (exception is IHasErrorCode hasErrorCodeException)
{
errorInfo.Code = hasErrorCodeException.Code;
}
return errorInfo;
}
}