我正在使用PostgreSQL编写Web api并在验证过程中检查数据库约束,但是我还有一个全局异常过滤器作为后备,以防万一保存时遇到了麻烦。我的问题是,异常似乎没有经过处理就可以呈现给客户端的任何消息。添加的图像来自断点的PostgresException数据。例如,在这种情况下,我想要类似“资产编号x已经存在”或“资产编号必须唯一”的名称。这可以在某处配置吗?最有意义的地方是约束创建代码,但我找不到这样做的选项。
modelBuilder.Entity<AssetItem>().HasIndex(item => new { item.AssetNumber }).IsUnique();
public class DbExceptionFilter : IExceptionFilter
{
private const string UNIQUE_EXCEPTION = "23505";
public async void OnException(ExceptionContext context)
{
var exceptionType = context.Exception.InnerException.GetType().FullName;
if (exceptionType == "Npgsql.PostgresException")
{
var pgException = (PostgresException) context.Exception.InnerException;
switch(pgException.SqlState)
{
case UNIQUE_EXCEPTION:
var error = new {error = "Unique Error Here"};
await WriteJsonErrorResponse(context.HttpContext.Response, HttpStatusCode.BadRequest, error);
return;
}
}
else
{
var error = new { error = "Unexpected Server Error"};
await WriteJsonErrorResponse(context.HttpContext.Response, HttpStatusCode.InternalServerError, error);
return;
}
}
private async Task WriteJsonErrorResponse(HttpResponse response, HttpStatusCode statusCode, dynamic error)
{
response.ContentType = "application/json";
response.StatusCode = (int) statusCode;
await response.Body.WriteAsync(Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(error)));
}
}
但是,一般而言,将数据库错误直接暴露给用户(包括Web API用户)不是一个好主意:这些错误旨在用于直接与数据库进行交互的应用程序(即您的应用程序)。这些消息通常对您的API用户没有多大意义,更重要的是,它们会泄漏有关您的数据库模式的潜在敏感信息,因此并不安全。在您似乎正在使用JsonConvert.SerializeObject进行转储/序列化整个异常给用户时,这尤其有问题。
这里的最佳实践是确定用户可能触发的合法数据库异常,拦截这些异常并返回您自己的消息,并用适当的措词(例如,“具有该名称的用户已存在”)。
作为说明,要识别PostgresException,而不是获取异常的名称并与之进行比较,您可以简单地使用C#模式匹配:
if (context.Exception.InnerException is PostgresException postgresException)
{
// ...
}