.NET 6 ActionFilter大请求体连续请求时内容混合及读取异常问题
问题:大体积XML请求体多次读取后内容损坏及并发读取异常
我们实现了自定义XmlValidationActionFilter,用于在控制器动作执行前对请求体执行XSD校验,确保XML格式合法。同时编写了HttpRequest扩展方法读取请求体,保证请求体可被多次读取。
当请求体未超过30KB阈值(不写入磁盘)时,XML校验正常;但当请求体超过该阈值时,首次请求可正常处理,后续对同一端点的请求内容出现损坏:部分XML被截断,有时会出现前一次请求的部分内容拼接下一次完整请求内容的情况。
现象示例
首次请求体
<?xml version="1.0" encoding="UTF-8"?> <TestXML> <Node1>Node1</Node1> <Node2> <CNode>Hello</CNode> </Node2 </TestXML>
后续请求1(内容截断)
<?xml version="1.0" encoding="UTF-8"?> <TestXML> <Node1>Node1</Node1> <Node2> <CNode>Hello</CNode>
后续请求2(内容拼接)
<?xml version="1.0" encoding="UTF-8"?> <TestXML> <Node1>Node1</Node1> <Node2> <CNode>Hello</CNode><?xml version="1.0" encoding="UTF-8"?> <TestXML> <Node1>Node1</Node1> <Node2> <CNode>Hello</CNode> </Node2 </TestXML>
相关代码
Startup.cs
services.AddScoped<XmlValidationActionFilter>();
app.Use(next => context => { context.Request.EnableBuffering(); return next(context); });
HttpRequest扩展方法
public static async Task<string> GetRequestBodyAsync(this HttpRequest request) { string requestBody = null; // IMPORTANT: Ensure the requestBody can be read multiple times. request.EnableBuffering(); // IMPORTANT: Leave the body open so the next middleware/filter/action can read it. using (var reader = new StreamReader( request.Body, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, leaveOpen: true)) { requestBody = await reader.ReadToEndAsync(); // IMPORTANT: Reset the request body stream position so the next middleware/filter/action can read it request.Body.Position = 0; } return requestBody; }
控制器使用示例
[ServiceFilter(typeof(XmlValidationActionFilter))] public async Task<IActionResult> SetRecord([FromHeader(Name = "SerialNumber")] string serialNumber) { var payload = await HttpContext.Request.GetRequestBodyAsync(); // 后续处理逻辑 }
补充异常信息
运行过程中还出现以下异常:
System.InvalidOperationException: Reading is already in progress. at System.IO.Pipelines.ThrowHelper.ThrowInvalidOperationException_AlreadyReading() at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result) at System.IO.Pipelines.Pipe.ReadAsync(CancellationToken token) at System.IO.Pipelines.Pipe.DefaultPipeReader.ReadAsync(CancellationToken cancellationToken) at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContext.ReadAsync(Memory`1 memory, CancellationToken cancellationToken) at Microsoft.AspNetCore.Server.IIS.Core.HttpRequestStream.ReadAsyncInternal(Memory`1 buffer, CancellationToken cancellationToken) at Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken) at System.IO.StreamReader.ReadBufferAsync(CancellationToken cancellationToken) at System.IO.StreamReader.ReadToEndAsyncInternal() Exception Info: System.InvalidOperationException: Concurrent reads or writes are not supported. at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result) at System.IO.Pipelines.Pipe.GetReadAsyncResult() at System.IO.Pipelines.Pipe.DefaultPipeReader.GetResult(Int16 token) at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContext.ReadAsync(Memory`1 memory, CancellationToken cancellationToken) at Microsoft.AspNetCore.Server.IIS.Core.HttpRequestStream.ReadAsyncInternal(Memory`1 buffer, CancellationToken cancellationToken) at Microsoft.AspNetCore.Server.IIS.Core.HttpRequestStream.ReadAsyncInternal(Memory`1 buffer, CancellationToken cancellationToken) at Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken) at Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken) at System.IO.StreamReader.ReadBufferAsync(CancellationToken cancellationToken) at System.IO.StreamReader.ReadBufferAsync(CancellationToken cancellationToken) at System.IO.StreamReader.ReadToEndAsyncInternal() at System.IO.StreamReader.ReadToEndAsyncInternal()
内容的提问来源于stack exchange,提问作者Kaizer69
相关产品推荐
相关产品推荐

