using Microsoft.AspNetCore.Http; using System.Buffers; namespace YLErp.Web.App { /// /// 异常处理中间件 /// internal class ExceptionMiddleware { private readonly RequestDelegate _next; public ExceptionMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { try { await _next.Invoke(context); } catch (Exception ex) { await HandleExceptionMessageAsync(context, ex); } } private static async Task HandleExceptionMessageAsync(HttpContext context, Exception exception) { var message = string.Empty; var serviceExpcetion = exception as ServiceException; var request = context.Request; try { // 暴露完整异常(类型 + 所有内层 message + 堆栈),不再只取最内层 message, // 便于定位根因(如 SacInfo 序列化 TypeId 触发的 IsGenericParameter 反射异常)。 message = exception.ToString(); 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}\r\n{message}"); } } catch (Exception ex) { message += "\r\n\r\n" + ex.Message; } if (request.Path.StartsWithSegments("/m/api", StringComparison.OrdinalIgnoreCase) || request.Headers["X-Requested-With"] == "XMLHttpRequest" && !request.Headers["Accept"].Contains("text/html")) { await context.Response.WriteAsJsonAsync(new { code = -1, success = false, msg = message, Data = serviceExpcetion?.Tag }); } else { context.Response.ContentType = "text/html"; var resultHtml = File.ReadAllText(Server.MapPath("Statics/html/ShowError.html")); resultHtml = resultHtml.Replace("{{ErrorMsg}}", message); await context.Response.WriteAsync(resultHtml); } } private static string ConvertBufferToString(in ReadOnlySequence readOnlySequence) { // Separate method because Span/ReadOnlySpan cannot be used in async methods ReadOnlySpan span = readOnlySequence.IsSingleSegment ? readOnlySequence.First.Span : readOnlySequence.ToArray().AsSpan(); return System.Text.Encoding.UTF8.GetString(span); } } }