diff --git a/YLErpWeb/App/ExceptionMiddleware.cs b/YLErpWeb/App/ExceptionMiddleware.cs index a0c469d2..86b10b6c 100644 --- a/YLErpWeb/App/ExceptionMiddleware.cs +++ b/YLErpWeb/App/ExceptionMiddleware.cs @@ -1,5 +1,7 @@ using Microsoft.AspNetCore.Http; using System.Buffers; +using System.Text; +using System.Text.Json; namespace YLErp.Web.App { @@ -17,6 +19,11 @@ namespace YLErp.Web.App public async Task Invoke(HttpContext context) { + if (IsSwapTradeEditRequest(context.Request)) + { + context.Request.EnableBuffering(); + } + try { await _next.Invoke(context); @@ -41,9 +48,17 @@ namespace YLErp.Web.App if (serviceExpcetion == null || serviceExpcetion.IsFaultError) { - var result = await request.BodyReader.ReadAsync(); - var reqBody = ConvertBufferToString(result.Buffer); - LogFactory.GetLogger(context.Request.Path.Value).Error(serviceExpcetion ?? exception, $"[query]:{request.QueryString.Value};[body]:{reqBody}"); + if (IsSwapTradeEditRequest(request)) + { + var diagnostic = await GetSwapIntervalDiagnosticAsync(request); + LogFactory.GetLogger(context.Request.Path.Value).Error(serviceExpcetion ?? exception, $"[query]:{request.QueryString.Value};{diagnostic}"); + } + else + { + var result = await request.BodyReader.ReadAsync(); + var reqBody = ConvertBufferToString(result.Buffer); + LogFactory.GetLogger(context.Request.Path.Value).Error(serviceExpcetion ?? exception, $"[query]:{request.QueryString.Value};[body]:{reqBody}"); + } } } catch (Exception ex) @@ -78,6 +93,106 @@ namespace YLErp.Web.App return System.Text.Encoding.UTF8.GetString(span); } + private static bool IsSwapTradeEditRequest(HttpRequest request) + { + return string.Equals(request.Path.Value, "/swaptrade2/tradeEditJson", StringComparison.OrdinalIgnoreCase); + } + + private static async Task GetSwapIntervalDiagnosticAsync(HttpRequest request) + { + if (!request.Body.CanSeek) + { + return "[swap-interval-diagnostic]:request-body-unavailable"; + } + + request.Body.Position = 0; + using var reader = new StreamReader(request.Body, Encoding.UTF8, false, 1024, leaveOpen: true); + var requestBody = await reader.ReadToEndAsync(); + request.Body.Position = 0; + + if (string.IsNullOrWhiteSpace(requestBody)) + { + return "[swap-interval-diagnostic]:request-body-empty"; + } + + try + { + using var document = JsonDocument.Parse(requestBody); + if (!document.RootElement.TryGetProperty("swap_positions", out var positions) || positions.ValueKind != JsonValueKind.Array) + { + return "[swap-interval-diagnostic]:swap_positions-missing"; + } + + var invalidRates = new List(); + var positionIndex = 0; + foreach (var position in positions.EnumerateArray()) + { + var positionId = position.TryGetProperty("id", out var id) ? id.ToString() : "missing"; + AddInvalidRateDiagnostics(position, "SwapIntervalList", false, positionIndex, positionId, invalidRates); + AddInvalidRateDiagnostics(position, "InterestSwapInterval", true, positionIndex, positionId, invalidRates); + if (position.TryGetProperty("Obervation", out var observation)) + { + AddInvalidRateDiagnostics(observation, "Obervation.ObservationInterval", true, positionIndex, positionId, invalidRates); + } + if (invalidRates.Count >= 10) + { + break; + } + positionIndex++; + } + + return invalidRates.Count == 0 + ? "[swap-interval-diagnostic]:no-invalid-rate-in-payload" + : $"[swap-interval-diagnostic]:{string.Join(";", invalidRates)}"; + } + catch (JsonException) + { + return "[swap-interval-diagnostic]:request-json-invalid"; + } + } + + private static void AddInvalidRateDiagnostics(JsonElement position, string source, bool serializedJson, int positionIndex, string positionId, List invalidRates) + { + if (!position.TryGetProperty(source, out var intervals)) + { + return; + } + + if (serializedJson) + { + if (intervals.ValueKind != JsonValueKind.String) + { + return; + } + + try + { + using var document = JsonDocument.Parse(intervals.GetString()); + intervals = document.RootElement.Clone(); + } + catch (JsonException) + { + invalidRates.Add($"positionIndex={positionIndex},positionId={positionId},source={source},interval-json-invalid"); + return; + } + } + + if (intervals.ValueKind != JsonValueKind.Array) + { + return; + } + + var intervalIndex = 0; + foreach (var interval in intervals.EnumerateArray()) + { + if ((!interval.TryGetProperty("Rate", out var rate) || rate.ValueKind == JsonValueKind.Null) && invalidRates.Count < 10) + { + invalidRates.Add($"positionIndex={positionIndex},positionId={positionId},source={source},intervalIndex={intervalIndex},rate={(rate.ValueKind == JsonValueKind.Null ? "null" : "missing")}"); + } + intervalIndex++; + } + } + private static string GetInnerExceptionMessage(Exception ex) { var exceptionStr = ex.Message; @@ -89,4 +204,4 @@ namespace YLErp.Web.App return exceptionStr; } } -} \ No newline at end of file +}