c# - WebAPI 过滤器的 ActionExecutedContext 中的异常属性为空
问题描述
几个月来,我一直在使用相同的异常过滤器,到目前为止它的表现非常完美。这里是:
public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter
{
public int Order { get; set; } = int.MaxValue - 10;
public void OnActionExecuting(ActionExecutingContext context)
{
}
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception is HttpResponseException exception)
{
context.Result = new ObjectResult(new {Mensagem = context.Exception.Message})
{
StatusCode = exception.Status,
};
context.ExceptionHandled = true;
}
else if (context.Exception is Exception)
{
var message = context.Exception.InnerException != null ? context.Exception.InnerException.Message : context.Exception.Message;
context.Result = new ObjectResult(new RetornoExceptionApi(message))
{
StatusCode = StatusCodes.Status500InternalServerError
};
context.ExceptionHandled = true;
}
}
}
简单直接。我一直在使用它来捕获HttpResponseException
作为基类的自定义 HTTP 异常。这是它的样子:
public class HttpResponseException : Exception
{
public int Status { get; set; } = StatusCodes.Status500InternalServerError;
public HttpResponseException(int statusCode)
{
Status = statusCode;
}
}
没什么。这是我对 404 状态代码的自定义异常:
public class NotFoundException404<TKey> : HttpResponseException
{
private string _message;
public NotFoundException404(TKey id) : base(StatusCodes.Status404NotFound)
{
_message = $"Nenhum objeto encontrado! ID solicitado: { id }";
}
public NotFoundException404(long id) : base(StatusCodes.Status404NotFound)
{
_message = $"Nenhum objeto encontrado! ID solicitado: { id }";
}
public NotFoundException404(string message) : base(StatusCodes.Status404NotFound)
{
_message = message;
}
public override string Message => _message;
}
示例用法(来自我的基础服务类):
protected virtual async Task<TEntity> GetWithFilterAsync(TKey id)
{
var entidade = await _repository.FirstOrDefaultAsync(GetFiltroListar(id));
if (entidade == null)
throw new NotFoundException404<TKey>(id);
return entidade;
}
就像我说的,这很好用,过滤器甚至可以捕获从框架内引发的异常。但是我必须创建一个自定义异常来处理外键违规,并且每当我抛出这个异常时,OnActionExecuted
都会调用过滤器,但context.Exception
它是空的。这是自定义异常:
public class ForeignKeyViolationException : Exception
{
public override string Message => "Registro possui dependências e não pode ser excluído";
public ForeignKeyViolationException() : base() { }
public ForeignKeyViolationException(string message) : base(message) { }
}
此异常是从与 HTTP 其他服务相同的基础服务引发的,如下所示:
protected async Task DeleteAsync(TKey id)
{
var entidade = await GetEntidadeExclusaoAsync(id);
try
{
await _repository.DeleteAsync(entidade);
}
catch (SqlException e) when (e.Number == 547)
{
throw new ForeignKeyViolationException();
}
catch (Exception ex)
{
if (ex.InnerException != null
&& ex is SqlException
&& ((SqlException)ex).Number == 547)
throw new ForeignKeyViolationException();
}
}
这不起作用(Exception
在null
我的过滤器中),我不知道为什么。任何指针?
解决方案
这里的主要问题似乎是我很愚蠢。我停下来以更彻底的方式检查代码,问题不在于过滤器,而在于我如何尝试提高ForeignKeyViolationException
. 这个:
catch (Exception ex)
{
if (ex.InnerException != null
&& ex is SqlException
&& ((SqlException)ex).Number == 547)
throw new ForeignKeyViolationException();
}
应该是这样的:
catch (Exception ex)
{
if (ex.InnerException != null
&& ex.InnerException is SqlException
&& ((SqlException)ex.InnerException).Number == 547)
throw new ForeignKeyViolationException();
else
throw ex;
}
“噗!”
更新
johnny 5's answer更干净,效果很好,这肯定是首选的方法:
catch (Exception ex) when ((ex.InnerException as SqlException)?.Number == 547)
{
throw new ForeignKeyViolationException();
}
推荐阅读
- c++ - 两次删除链表有什么区别?
- python - Skip-gram word2vec 损失没有减少
- css - 弹性项目和换行符
- mongodb - 如果负载不足,MongoDB TTL 不会删除文档
- c++ - 外部 RAM 中的动态向量分配
- html - 图像从 CSS Grid 项中的父 div 溢出(仅限 Firefox)
- ruby-on-rails - Rails:无法为没有模型 ID 的模型创建全局 ID
- php - PHP Slash 没有抛出 404
- javascript - 如何在网页中显示数组的完整对象?
- postgresql - 无法连接到 psql 控制台:psql: FATAL: Peer authentication failed for user "postgres"