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);
}
}
}