我正在使用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)));
}
}
答案 0 :(得分:1)
PostgreSQL提供的与用户可读消息最接近的是PostgresException上显示的消息文本。
但是,一般而言,将数据库错误直接暴露给用户(包括Web API用户)不是一个好主意:这些错误旨在用于直接与数据库进行交互的应用程序(即您的应用程序)。这些消息通常对您的API用户没有多大意义,更重要的是,它们会泄漏有关数据库架构的潜在敏感信息,因此并不安全。像您正在做的那样(使用JsonConvert.SerializeObject)将整个异常转储/序列化给用户,这尤其有问题。
此处的最佳做法是识别用户可能触发的合法数据库异常,拦截这些异常并返回您自己的消息,并用适当的措词(例如,“具有该名称的用户已经存在”)。
作为旁注,要标识PostgresException,而不必获取异常的名称并与之进行比较,您可以简单地使用C#模式匹配:
if (context.Exception.InnerException is PostgresException postgresException)
{
// ...
}