从Npgsql.PostgresException获取客户端可读消息

问题描述 投票:0回答:1

我正在使用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)));
    }
}

Exception Properties

asp.net-core ef-code-first npgsql
1个回答
0
投票
PostgreSQL提供的与用户可读消息最接近的消息是PostgresException上显示的消息文本。

但是,一般而言,将数据库错误直接暴露给用户(包括Web API用户)不是一个好主意:这些错误旨在用于直接与数据库进行交互的应用程序(即您的应用程序)。这些消息通常对您的API用户没有多大意义,更重要的是,它们会泄漏有关您的数据库模式的潜在敏感信息,因此并不安全。在您似乎正在使用JsonConvert.SerializeObject进行转储/序列化整个异常给用户时,这尤其有问题。

这里的最佳实践是确定用户可能触发的合法数据库异常,拦截这些异常并返回您自己的消息,并用适当的措词(例如,“具有该名称的用户已存在”)。

作为说明,要识别PostgresException,而不是获取异常的名称并与之进行比较,您可以简单地使用C#模式匹配:

if (context.Exception.InnerException is PostgresException postgresException) { // ... }

© www.soinside.com 2019 - 2024. All rights reserved.