C# .Net核心中间件httpContext不支持并发读写

C# .Net核心中间件httpContext不支持并发读写,c#,.net-core,asp.net-core-middleware,C#,.net Core,Asp.net Core Middleware,我在.NETCore中添加了一个中间件,它记录每个api请求和对nLog的响应。它对我来说很好,甚至没有发现任何问题。 今天我试图向API发出批量请求,但收到了一个异常 不支持并发读取或写入 在等待HttpContext.Request.Body.ReadAsync(buffer,0,buffer.Length)其中buffer为var buffer=new byte[Convert.ToInt32(HttpContext.Request.ContentLength)] 我在这个层面上有些困惑

我在.NETCore中添加了一个中间件,它记录每个api请求和对nLog的响应。它对我来说很好,甚至没有发现任何问题。 今天我试图向API发出批量请求,但收到了一个异常

不支持并发读取或写入 在
等待HttpContext.Request.Body.ReadAsync(buffer,0,buffer.Length)
其中buffer为
var buffer=new byte[Convert.ToInt32(HttpContext.Request.ContentLength)]

我在这个层面上有些困惑

  • Net core是否为每个请求创建单独的管道。我认为是的,作为HttpContext。每个请求周期的项目都是唯一的
  • 如果是,那么我为什么会收到并发错误。作为我的代码,首先记录请求,然后将上下文传递给下一个中间件,最后记录响应。(我是否遗漏了什么?)
  • 如果您能分享克服此问题的更好方法,请联系我们

    下面是代码供参考

     public class LoggingMiddleware
    {
        readonly ILogger logger;
        readonly RequestDelegate next;
        public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger)
        {
            this.logger = logger;
            this.next = next;
        }
    
        public async Task Invoke(HttpContext context)
        {
            LogRequest(context);
            var originalBodyStream = context.Response.Body;
            using (var responseBody = new MemoryStream())
            {
                context.Response.Body = responseBody;
                await next(context).ConfigureAwait(false);
                LogResponse(context);
                await responseBody.CopyToAsync(originalBodyStream).ConfigureAwait(false);
            }
        }
        private async void LogRequest(HttpContext context)
        {
            var request = context.Request;
            request.EnableRewind();
            var buffer = new byte[Convert.ToInt32(request.ContentLength)];
            await request.Body.ReadAsync(buffer, 0, buffer.Length);
            string requestBody = Encoding.UTF8.GetString(buffer);
            request.Body.Seek(0, SeekOrigin.Begin);
            context.Items["Request"] = requestBody;     //Request is being used in Nlog config
            logger.LogInformation("Request received ......");       // Some information
    
            context.Items.Remove("Request");
        }
    
        private async void LogResponse(HttpContext context)
        {
            var response = context.Response;
            response.Body.Seek(0, SeekOrigin.Begin);
            var responseText = await new StreamReader(response.Body).ReadToEndAsync().ConfigureAwait(false);
            response.Body.Seek(0, SeekOrigin.Begin);
    
            context.Items["Response"] = responseText;
            logger.LogInformation("Returned response for url with status");     // Information
            context.Items.Remove("Response");
        }
    
    }
    
    公共类日志中间件
    {
    只读ILogger记录器;
    只读请求委托下一步;
    公共日志中间件(RequestDelegate next,ILogger logger)
    {
    this.logger=记录器;
    this.next=next;
    }
    公共异步任务调用(HttpContext上下文)
    {
    日志请求(上下文);
    var originalBodyStream=context.Response.Body;
    使用(var responseBody=newmemorystream())
    {
    context.Response.Body=responseBody;
    等待下一步(上下文)。配置等待(false);
    日志响应(上下文);
    wait responseBy.CopyToAsync(原始BodyStream).ConfigureWait(false);
    }
    }
    专用异步void日志请求(HttpContext上下文)
    {
    var-request=context.request;
    request.EnableRewind();
    var buffer=新字节[Convert.ToInt32(request.ContentLength)];
    wait request.Body.ReadAsync(buffer,0,buffer.Length);
    string requestBody=Encoding.UTF8.GetString(缓冲区);
    request.Body.Seek(0,SeekOrigin.Begin);
    context.Items[“Request”]=requestBody;//请求正在Nlog配置中使用
    logger.LogInformation(“收到请求……”;//一些信息
    上下文。项目。删除(“请求”);
    }
    专用异步void日志响应(HttpContext上下文)
    {
    var-response=context.response;
    response.Body.Seek(0,SeekOrigin.Begin);
    var responseText=await new StreamReader(response.Body).ReadToEndAsync().ConfigureAwait(false);
    response.Body.Seek(0,SeekOrigin.Begin);
    context.Items[“Response”]=responseText;
    logger.LogInformation(“返回的url响应状态”);//信息
    上下文。项目。删除(“响应”);
    }
    }
    
    ASP.NET总是为不同的请求使用不同的线程。HttpContext引用一个特定的请求。这在.NETCore中没有改变。至于错误-代码在哪里?既然代码已经在自己的线程上运行,为什么还要尝试使用另一个线程来访问上下文?您是否使用了
    ConfigureAwait(false)
    也许?当你的方法很可能已经可以访问请求正文时,为什么要使用
    Request.Body
    ?请在问题本身中张贴你的代码。不要发布无关文章的链接-这两篇文章是关于日志记录的,而不是关于对HttpContext的跨线程访问您是否可以使用
    \u next(上下文)而不是
    等待下一步(上下文)在中间件中?@PanagiotisKanavos Aha!我明白你的意思。是的,我使用的是异步方法,它可能会产生问题。我已经在使用ConfigureAwait(false),但尚未解决。我将再次尝试同步方法,希望我能解决这个问题。正如我所解释的,对于request.Body,它是一个中间件,此时我只能从httpContext读取请求体。感谢您的回复
    configurewait(false)
    很可能是问题的原因。不要尝试同步方法。张贴代码。不要假设ASP.NET核心是断线的。ASP.NET总是为不同的请求使用不同的线程。HttpContext引用一个特定的请求。这在.NETCore中没有改变。至于错误-代码在哪里?既然代码已经在自己的线程上运行,为什么还要尝试使用另一个线程来访问上下文?您是否使用了
    ConfigureAwait(false)
    也许?当你的方法很可能已经可以访问请求正文时,为什么要使用
    Request.Body
    ?请在问题本身中张贴你的代码。不要发布无关文章的链接-这两篇文章是关于日志记录的,而不是关于对HttpContext的跨线程访问您是否可以使用
    \u next(上下文)而不是
    等待下一步(上下文)在中间件中?@PanagiotisKanavos Aha!我明白你的意思。是的,我使用的是异步方法,它可能会产生问题。我已经在使用ConfigureAwait(false),但尚未解决。我将再次尝试同步方法,希望我能解决这个问题。正如我所解释的,对于request.Body,它是一个中间件,此时我只能从httpContext读取请求体。感谢您的回复
    configurewait(false)
    很可能是问题的原因。不要尝试同步方法。张贴代码。不要假设ASP.NET核心已损坏