来自 WebAPI 过滤器的 ActionExecutedContext 中的异常 属性 为空
Exception property in ActionExecutedContext from WebAPI filter is null
几个月来我一直在使用同一个异常过滤器,到目前为止它的表现一直很完美。这是:
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;
}
}
}
简单明了。我一直在使用它来捕获自定义 HTTP 异常,HttpResponseException
是基础 class。这是它的样子:
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;
}
示例用法(这是来自我的基本服务 class):
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;
}
"Derp!"
更新
johnny 5 的回答更简洁并且运行完美,这无疑是首选的方式:
catch (Exception ex) when ((ex.InnerException as SqlException)?.Number == 547)
{
throw new ForeignKeyViolationException();
}
看来您已经找到问题的答案了。但是,我会努力以您的回答为基础。您可以使用 when 子句使函数更具可读性。
catch (Exception ex) when ((ex.InnerException as SqlException)?.Number == 547) {
throw new ForeignKeyViolationException();
}
几个月来我一直在使用同一个异常过滤器,到目前为止它的表现一直很完美。这是:
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;
}
}
}
简单明了。我一直在使用它来捕获自定义 HTTP 异常,HttpResponseException
是基础 class。这是它的样子:
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;
}
示例用法(这是来自我的基本服务 class):
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;
}
"Derp!"
更新
johnny 5 的回答更简洁并且运行完美,这无疑是首选的方式:
catch (Exception ex) when ((ex.InnerException as SqlException)?.Number == 547)
{
throw new ForeignKeyViolationException();
}
看来您已经找到问题的答案了。但是,我会努力以您的回答为基础。您可以使用 when 子句使函数更具可读性。
catch (Exception ex) when ((ex.InnerException as SqlException)?.Number == 547) {
throw new ForeignKeyViolationException();
}