文章目录
中间件记录全局日志/出入参数:
日志记录中间件
遇到的问题(踩过的坑)
-
- Specified method is not supported. 不支持指定的方法
-
- Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead. 不允许同步操作。
-
- Stream was not readable. 流不可读取
-
- A non-empty request body is required. 空的请求主体
-
- Concurrent reading is not supported. 不支持并发读取
Stream was not readable. 流不可读取/Specified method is not supported. 不支持指定的方法
.net Core 3的Request.Body默认不允许设置位置,不允许读取等
//启用读取request
httpContext.Request.EnableBuffering();
Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead. 不允许同步操作。
发生原因: .net Core 3以上Request.Body的流不允许同步读取,使用
var requestContent = await requestReader.ReadToEndAsync(); 异步读取
await/ReadToEndAsync().Result; 同步读取值
A non-empty request body is required. 空的请求主体
在读取完后日志记录下来,报这个错误,对比发现Body流的位置不在0了,导致控制器模型绑定的时候报错.
request.Body.Position = 0;
完整代码
public async Task InvokeAsync(HttpContext httpContext)
{
//启用读取request
httpContext.Request.EnableBuffering();
//请求body
using var requestReader = new StreamReader(request.Body);
var requestContent = await requestReader.ReadToEndAsync();
request.Body.Position = 0;
//设置stream存放ResponseBody
var responseOriginalBody = response.Body;
using var memStream = new MemoryStream();
response.Body = memStream;
// 执行其他中间件
await _next(httpContext);
//处理执行其他中间件后的ResponseBody
memStream.Position = 0;
var responseReader = new StreamReader(memStream);
var responseContent = await responseReader.ReadToEndAsync();
memStream.Position = 0;
await memStream.CopyToAsync(responseOriginalBody);
response.Body = responseOriginalBody;
this._factory.CreateLogger<LogRequestMiddleware>().LogInformation($"请求方式: {request.Method} URL: {reqUrl} \r\n 参数: {requestContent}\r\n \r\n ");
this._factory.CreateLogger<LogRequestMiddleware>().LogInformation($"日志返回: {request.Method} URL: {reqUrl} \r\n 参数: {responseContent}\r\n \r\n ");
}
异常记录中间件
非常简单,没什么可说的
/// <summary>
/// 异常记录中间件
/// </summary>
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private ILoggerFactory _factory;
/// <summary>
/// 异常
/// </summary>
/// <param name="next"></param>
/// <param name="factory"></param>
public ExceptionMiddleware(RequestDelegate next, ILoggerFactory factory)
{
_next = next;
this._factory = factory;
}
public async Task Invoke(HttpContext httpContext)
{
try
{
await _next.Invoke(httpContext);
}
catch (Exception ex)
{
await HandleError(httpContext, ex);
}
}
/// <summary>
/// 错误信息处理方法
/// </summary>
/// <param name="context"></param>
/// <param name="ex"></param>
/// <returns></returns>
private async Task HandleError(HttpContext context, Exception ex)
{
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json;";
string errorMsg = $"\r\n错误消息:{ex.Message}{Environment.NewLine}\r\n错误追踪:{ex.StackTrace}";
this._factory.CreateLogger<LogRequestMiddleware>().LogError(errorMsg);
//处理各种异常
ResponseBase<object> response = ResponseBase<object>.Error("系统错误");
var respStr = response.ToJson();
var by = Encoding.UTF8.GetBytes(respStr);
await context.Response.Body.WriteAsync(by, 0, by.Length);
}
}
使用方法
写在跨域/路由/静态目录等系统中间件之后, 控制器中间件之前.
app.UseMiddleware();
app.UseMiddleware();