Получение читаемого клиентом сообщения из Npg sql .PostgresException - PullRequest
0 голосов
/ 03 февраля 2020

Я пишу веб-API с использованием PostgreSQL и проверяю ограничения базы данных как часть процесса проверки, но у меня также есть глобальный фильтр исключений в качестве запасного варианта на случай, если что-то случится при сохранении. Моя проблема в том, что исключение, похоже, не содержит сообщений, которые я могу представить клиенту без какой-либо обработки. Добавленное изображение содержит данные 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

1 Ответ

1 голос
/ 03 февраля 2020

Самым близким к читаемому пользователем сообщению, которое предоставляет PostgreSQL, является текст сообщения, отображаемый в PostgresException.

Однако, как правило, не рекомендуется представлять ошибки базы данных непосредственно пользователям. (включая пользователей веб-API): они предназначены для приложения, непосредственно взаимодействующего с базой данных (т.е. вашего приложения). Эти сообщения, как правило, мало что значат для пользователей вашего API, и что более важно, они пропускают потенциально конфиденциальную информацию о вашей схеме базы данных и, следовательно, не являются безопасными. Это особенно проблематично c, чтобы выгрузить / сериализовать все исключение для пользователя, как вы, кажется, делаете (с JsonConvert.SerializeObject).

Лучшей практикой здесь будет определение допустимых исключений базы данных, которые пользователь может вызвать, перехватить их и вернуть собственное сообщение с соответствующим названием (например, «Пользователь с таким именем уже существует»).

В качестве примечания, чтобы идентифицировать PostgresException, а не получать имя исключения и по сравнению с этим вы можете просто использовать C# сопоставление с образцом:

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