Asp.net core HTTP主体日志中间件性能瓶颈
我试图编写一个中间件,记录应用程序发送给客户端的每个请求和响应的主体。然而,应用程序的性能变得非常糟糕,以至于一个普通请求在80秒后收到响应Asp.net core HTTP主体日志中间件性能瓶颈,asp.net-core,asp.net-core-webapi,middleware,Asp.net Core,Asp.net Core Webapi,Middleware,我试图编写一个中间件,记录应用程序发送给客户端的每个请求和响应的主体。然而,应用程序的性能变得非常糟糕,以至于一个普通请求在80秒后收到响应 公共类日志中间件 { 私有请求委托_next; 专用只读ILogger\u记录器; 公共日志中间件(ILogger记录器,RequestDelegate next) { _记录器=记录器; _下一个=下一个; } 公共异步任务InvokeAsync(HttpContext上下文) { StringBuilder日志=新建StringBuilder(); 尝
公共类日志中间件
{
私有请求委托_next;
专用只读ILogger\u记录器;
公共日志中间件(ILogger记录器,RequestDelegate next)
{
_记录器=记录器;
_下一个=下一个;
}
公共异步任务InvokeAsync(HttpContext上下文)
{
StringBuilder日志=新建StringBuilder();
尝试
{
//请求
log.Append($“A{context.Request.Method}请求到达{context.Request.Path}{context.Request.QueryString.ToString()}”);
log.Append($”\n请求时间(本地):{DateTime.Now.ToString(“r”)});
if(context.Request.Method.Equals(“POST”,StringComparison.OrdinalIgnoreCase))
{
context.Request.enableBuffer();
使用(var reader=newstreamreader(context.Request.Body,System.Text.Encoding.UTF8,true,1024,true))
{
string body=wait reader.ReadToEndAsync();
string bodyLog=!string.IsNullOrEmpty(正文)?正文:“空”;
追加($“\n正文:{bodyLog}”);
context.Request.Body.Seek(0,SeekOrigin.Begin);
}
}
//回应
var originalBodyStream=context.Response.Body;
使用(var responseBody=newmemorystream())
{
context.Response.Body=responseBody;
//调用下一个中间件
等待下一步(上下文);
var-response=context.response;
response.Body.Seek(0,SeekOrigin.Begin);
string responseText=等待新的StreamReader(response.Body).ReadToEndAsync();
string bodyLog=!string.IsNullOrEmpty(responseText)?responseText:“空”;
response.Body.Seek(0,SeekOrigin.Begin);
log.Append($”\n响应时间(本地):{DateTime.Now.ToString(“r”)});
log.Append($“\n响应状态:{context.Response.StatusCode}”);
追加($“\n正文:{bodyLog}”);
wait responseBody.CopyToAsync(originalBodyStream);
}
}
抓住
{
投掷;
}
最后
{
等待任务。运行(()=>
{
_logger.Log(Log.ToString());
返回Task.CompletedTask;
});
}
}
}
我不太清楚为什么会这样,但很明显我在这里做错了什么。我能做些什么来改进和优化代码,使其运行更流畅
除此之外,我还有一个自定义属性,用于验证目的的一些操作之上,它必须生成正文内容的散列。即使删除中间件(或属性),性能仍然很差,但它们都是日志记录和验证所必需的
公共类SignatureValidationAttribute:ActionFilterAttribute
{
public SignatureValidationAttribute(){}
公共重写无效OnActionExecuting(ActionExecutingContext上下文)
{
HttpRequest请求=context.HttpContext.request;
IServiceProvider serviceProvider=context.HttpContext.RequestServices;
if(request.Headers.TryGetValue(“签名”,out-StringValues))
{
context.HttpContext.Request.enableBuffer();
使用(var reader=newstreamreader(request.Body,System.Text.Encoding.UTF8,true,1024,true))
{
request.Body.Seek(0,SeekOrigin.Begin);
var jsonBody=reader.ReadToEnd();
request.Body.Seek(0,SeekOrigin.Begin);
var signatureService=(ISignatureService)serviceProvider.GetService(typeof(ISignatureService));//MD5
string hash=signatureService.GenerateSignature(jsonBody,“SOMEKEY”);
if(values.First()!=hash)
{
context.Result=新的未授权对象结果(新的
{
ErrorMessage=“无效哈希”
});
}
}
}
}
}
您是否调整了
StreamReader
的构造函数?当您试图读取响应正文(除非非常小)时,1kb的缓冲区大小似乎很小,并且在使用块的结尾处处理流后,也会使流保持打开状态。同样在中间件的响应端,它似乎将context.response.Body
设置为new MemoryStream()
,然后将其作为new StreamReader()
读取。我没有调整构造函数,是的,响应非常小,所以应该不是什么大问题-我从测试端点I 639B得到的响应。尽管如此,我还是会增加。至于新的MemoryStream()
,是的,但是应用程序会写入新的流,这样我就可以从中读取多次。您是否调整了StreamReader
的构造函数?当您试图读取响应正文(除非非常小)时,1kb的缓冲区大小似乎很小,并且在使用
块的结尾处处理流后,也会使流保持打开状态。同样在中间件的响应端,它似乎设置了<