.Net核心中间件httpContext不支持并发读写 Concurrent reads or writes are not supported.

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

Concurrent reads or writes are not supported.

writing is not allowed after writer was completed

 

看到早上的日出,今天又是充满希望的一天,开开心心上班到中午,系统出现一个神奇的问题。国内度神上狂搜,结果哪,没什么结果....搬个梯子去google看看,可能梯子午睡还没醒,10个网页9个打不开.。也许真的是充满希望的一天,在google上只打开了两个网页,其中一个就是解决方案。

 

环境:net core 5.0   web api  +  ES

我在.Net核心中添加了一个中间件,该中间件记录了每个api请求和对nLog的响应。它对我来说很好用,即使没有发现任何问题。今天,我试图向API发出批量请求,但收到了异常,这是个很异常很有意思,第一次请求接口可正常访问,第二次出现异常“Concurrent reads or writes are not supported.”,这个错误,只有使用 Framework 程序访问才会出现。

 

 1 {
 2     "Timestamp":"2021-03-02T15:21:17.6426051+08:00",
 3     "Level":"Error",
 4     "MessageTemplate":"Unexpected exception in \"{ClassName}.{MethodName}\".",
 5     "Exception":"System.InvalidOperationException: Writing is not allowed after writer was completed.\r\n   
 6         at System.IO.Pipelines.ThrowHelper.ThrowInvalidOperationException_NoWritingAllowed()\r\n   
 7         at System.IO.Pipelines.Pipe.GetMemory(Int32 sizeHint)\r\n   
 8         at System.IO.Pipelines.Pipe.DefaultPipeWriter.GetMemory(Int32 sizeHint)\r\n   
 9         at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContext.ReadBody()",
10     "Properties":
11     {
12         "ClassName":"IISHttpContext",
13         "MethodName":"ReadBody",
14         "EventId":
15         {
16             "Id":3,
17             "Name":"UnexpectedError"
18         },
19         "SourceContext":"Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer",
20         "RequestId":"8000bab3-0000-ff00-b63f-84710c7967bb",
21         "RequestPath":"/api/v1/ProductBatch/ProductBatchAdd"
22     }
23 }

换了另一个日志记录,出现另一个错误“writing is not allowed after writer was completed”

1 [18:00:37 ERR] Unexpected exception in "IISHttpContext.ReadBody".
2 System.InvalidOperationException: Writing is not allowed after writer was completed.
3    at System.IO.Pipelines.ThrowHelper.ThrowInvalidOperationException_NoWritingAllowed()
4    at System.IO.Pipelines.Pipe.GetMemory(Int32 sizeHint)
5    at System.IO.Pipelines.Pipe.DefaultPipeWriter.GetMemory(Int32 sizeHint)
6    at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContext.ReadBody()

 

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

我在这个水平上有些困惑

  1. .Net核心是否为每个请求创建单独的管道。我认为是的,因为HttpContext.Items对于每个请求周期都是唯一的。
  2. 如果是,那为什么我会收到并发错误。作为我的代码,首先记录请求,然后将上下文传递给下一个中间件,最后记录响应。

请您分享更好的方法来解决此问题。

 1  public class LoggingMiddleware
 2 {
 3     readonly ILogger logger;
 4     readonly RequestDelegate next;
 5     public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger)
 6     {
 7         this.logger = logger;
 8         this.next = next;
 9     }
10 
11     public async Task Invoke(HttpContext context)
12     {
13         LogRequest(context);
14         var originalBodyStream = context.Response.Body;
15         using (var responseBody = new MemoryStream())
16         {
17             context.Response.Body = responseBody;
18             await next(context).ConfigureAwait(false);
19             LogResponse(context);
20             await responseBody.CopyToAsync(originalBodyStream).ConfigureAwait(false);
21         }
22     }
23     private async void LogRequest(HttpContext context)
24     {
25         var request = context.Request;
26         request.EnableRewind();
27         var buffer = new byte[Convert.ToInt32(request.ContentLength)];
28         await request.Body.ReadAsync(buffer, 0, buffer.Length);
29         string requestBody = Encoding.UTF8.GetString(buffer);
30         request.Body.Seek(0, SeekOrigin.Begin);
31         context.Items["Request"] = requestBody;     //Request is being used in Nlog config
32         logger.LogInformation("Request received ......");       // Some information
33 
34         context.Items.Remove("Request");
35     }
36 
37     private async void LogResponse(HttpContext context)
38     {
39         var response = context.Response;
40         response.Body.Seek(0, SeekOrigin.Begin);
41         var responseText = await new StreamReader(response.Body).ReadToEndAsync().ConfigureAwait(false);
42         response.Body.Seek(0, SeekOrigin.Begin);
43 
44         context.Items["Response"] = responseText;
45         logger.LogInformation("Returned response for url with status");     // Information
46         context.Items.Remove("Response");
47     }
48 
49 }

主要问题出在“ await request.Body.ReadAsync(buffer, 0, buffer.Length); ” ,需要使用 await 修改为同步模式。

 

 

参考

https://stackoverflow.com/questions/58095947/net-core-middleware-httpcontext-concurrent-read-and-write-not-supported

 

posted @ 2021-03-03 09:48  ypeuee  阅读(549)  评论(1编辑  收藏  举报