| | | 1 | | using System.Net; |
| | | 2 | | using Services.ApiServices._1CApi.OData.Models; |
| | | 3 | | |
| | | 4 | | namespace Services.ApiServices._1CApi.OData; |
| | | 5 | | |
| | | 6 | | /// <summary> |
| | | 7 | | /// Ошибка обмена с 1С OData в одном формате для любого метода клиента: что вызывали, что вернула 1С и |
| | | 8 | | /// текст ответа целиком (без усечения до 500 символов, которое остаётся только у пользовательских сообщений). |
| | | 9 | | /// </summary> |
| | 24 | 10 | | public sealed record OneCODataError( |
| | 14 | 11 | | string Method, |
| | 12 | 12 | | string Endpoint, |
| | 14 | 13 | | int StatusCode, |
| | 0 | 14 | | string? ReasonPhrase, |
| | 22 | 15 | | string? Code, |
| | 15 | 16 | | string Message, |
| | 27 | 17 | | string? RawBody) |
| | | 18 | | { |
| | | 19 | | /// <summary>Потолок сырого тела: защита от многомегабайтной HTML-страницы вместо OData-ошибки.</summary> |
| | | 20 | | public const int RawBodyMaxLength = 16000; |
| | | 21 | | |
| | | 22 | | /// <summary>Подпись для логов и поля «ответ 1С»: статус, код 1С и полный текст причины.</summary> |
| | | 23 | | public string ToDetailText() |
| | | 24 | | { |
| | 10 | 25 | | var code = string.IsNullOrWhiteSpace(Code) ? string.Empty : $" [{Code}]"; |
| | 10 | 26 | | return $"HTTP {StatusCode}{code} {Method} {Endpoint}: {Message}"; |
| | | 27 | | } |
| | | 28 | | |
| | | 29 | | public static OneCODataError From(string method, string endpoint, HttpStatusCode status, string? reason, string? bod |
| | | 30 | | { |
| | 17 | 31 | | var message = OneCODataErrorFormatter.Format(body); |
| | 17 | 32 | | if (string.IsNullOrWhiteSpace(message)) |
| | 2 | 33 | | message = "(пустое тело)"; |
| | | 34 | | |
| | 17 | 35 | | var raw = string.IsNullOrEmpty(body) |
| | 17 | 36 | | ? null |
| | 17 | 37 | | : body.Length <= RawBodyMaxLength ? body : body[..RawBodyMaxLength] + "…"; |
| | | 38 | | |
| | 17 | 39 | | return new OneCODataError(method, endpoint, (int)status, reason, |
| | 17 | 40 | | OneCODataErrorFormatter.TryExtractODataCode(body), message, raw); |
| | | 41 | | } |
| | | 42 | | } |
| | | 43 | | |
| | | 44 | | /// <summary> |
| | | 45 | | /// Любая ошибка ответа 1С OData. Наследуется от <see cref="InvalidOperationException"/>, чтобы не ломать |
| | | 46 | | /// код, который уже ловит ошибки клиента по базовому типу; полные данные ответа — в <see cref="Error"/>. |
| | | 47 | | /// </summary> |
| | | 48 | | public class OneCODataException(string message, OneCODataError? error = null) |
| | | 49 | | : InvalidOperationException(message) |
| | | 50 | | { |
| | | 51 | | public OneCODataError? Error { get; } = error; |
| | | 52 | | } |