Я попытался написать промежуточное программное обеспечение, которое регистрирует каждое тело каждого запроса и ответа, которое приложение отправляет клиенту. Однако производительность приложения сильно ухудшилась, настолько, что обычный запрос получает ответ через 80 секунд.
public class LoggingMiddleware
{
private RequestDelegate _next;
private readonly ILogger _logger;
public LoggingMiddleware(ILogger logger, RequestDelegate next)
{
_logger = logger;
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
StringBuilder log = new StringBuilder();
try
{
// Request
log.Append($"A {context.Request.Method} request arrived at {context.Request.Path} {context.Request.QueryString.ToString()}");
log.Append($"\nRequest time (local): {DateTime.Now.ToString("r")}");
if (context.Request.Method.Equals("POST", StringComparison.OrdinalIgnoreCase))
{
context.Request.EnableBuffering();
using (var reader = new StreamReader(context.Request.Body, System.Text.Encoding.UTF8, true, 1024, true))
{
string body = await reader.ReadToEndAsync();
string bodyLog = !string.IsNullOrEmpty(body) ? body : "EMPTY";
log.Append($"\nBody: {bodyLog}");
context.Request.Body.Seek(0, SeekOrigin.Begin);
}
}
// Response
var originalBodyStream = context.Response.Body;
using (var responseBody = new MemoryStream())
{
context.Response.Body = responseBody;
// Invoke next middleware
await _next(context);
var response = context.Response;
response.Body.Seek(0, SeekOrigin.Begin);
string responseText = await new StreamReader(response.Body).ReadToEndAsync();
string bodyLog = !string.IsNullOrEmpty(responseText) ? responseText : "EMPTY";
response.Body.Seek(0, SeekOrigin.Begin);
log.Append($"\nResponse time (local): {DateTime.Now.ToString("r")}");
log.Append($"\nResponse status: {context.Response.StatusCode}");
log.Append($"\nBody: {bodyLog}");
await responseBody.CopyToAsync(originalBodyStream);
}
}
catch
{
throw;
}
finally
{
await Task.Run(() =>
{
_logger.Log(log.ToString());
return Task.CompletedTask;
});
}
}
}
Я не совсем уверен, почему это так, но ясно, что я делаю что-то не так здесь. Есть ли что-то, что я могу сделать, чтобы улучшить и оптимизировать код, чтобы он работал более плавно?
Кроме того, у меня есть пользовательский атрибут, который используется поверх нескольких действий в целях проверки, и он должен генерировать ха sh содержимого тела. Производительность остается плохой даже после удаления промежуточного программного обеспечения (или атрибута), но они оба необходимы для ведения журнала и проверки.
public class SignatureValidationAttribute : ActionFilterAttribute
{
public SignatureValidationAttribute() { }
public override void OnActionExecuting(ActionExecutingContext context)
{
HttpRequest request = context.HttpContext.Request;
IServiceProvider serviceProvider = context.HttpContext.RequestServices;
if (request.Headers.TryGetValue("Signature", out StringValues values))
{
context.HttpContext.Request.EnableBuffering();
using (var reader = new StreamReader(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 = new UnauthorizedObjectResult(new
{
ErrorMessage = "Invalid hash"
});
}
}
}
}
}