Blazor WASM控制器:读取请求体导致IIS进程崩溃



所以我试图简单地在Blazor WASM ApiController中读取body(带有字符串内容)。我在服务器端的代码:

[AllowAnonymous]
[ApiController]
[Route("[controller]")]
public class SmartMeterDataController : ControllerBase
{
[HttpPost("UploadData")]
public async void UploadData()
{
string body = null;
if (Request.Body.CanRead && (Request.Method == HttpMethods.Post || Request.Method == HttpMethods.Put))
{
Request.EnableBuffering();
Request.Body.Position = 0;
body = await new StreamReader(Request.Body).ReadToEndAsync();
}
}
}

我的app builder在Program.cs中几乎是开箱即用的:

//enable REST API controllers
var mvcBuillder = builder.Services.AddMvcCore(setupAction: options => options.EnableEndpointRouting = false).ConfigureApiBehaviorOptions(options => //activate MVC and configure error handling
{
options.InvalidModelStateResponseFactory = context => //error 400 (bad request)
{
JsonApiErrorHandler.HandleError400BadRequest(context);
return new Microsoft.AspNetCore.Mvc.BadRequestObjectResult(context.ModelState);
};
});
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
...
app.UseRouting();
app.UseMvcWithDefaultRoute();
app.MapRazorPages();
app.MapControllers();

请求正文如下:

{"api_key";K12345667565656";field1"; "1.10";field2"; "0.76";field3":"0.65";field4"; "455";field5"; "0";;field6";"field7"433761","field8":"11815";}

是的,这是JSON。不,我不想用[FromBody]或类似的方法解析它。

发送到该端点会导致以下异常(如在Windows事件查看器中所见):

Application: w3wp.exe
CoreCLR Version: 6.0.1222.56807
.NET Version: 6.0.12
Description: The process was terminated due to an unhandled exception.
Exception Info: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'HttpRequestStream'.
at Microsoft.AspNetCore.Server.IIS.Core.HttpRequestStream.ValidateState(CancellationToken cancellationToken)
at Microsoft.AspNetCore.Server.IIS.Core.HttpRequestStream.ReadAsync(Memory`1 destination, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Server.IIS.Core.WrappingStream.ReadAsync(Memory`1 destination, 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()

之后,总是记录第二个错误。它陈述了一些类似于这里描述的东西。请注意,通常不是第一个POST,而是第二个或第三个POST导致这种情况。在此之后,每次POST都会发生错误,过了一会儿应用程序停止工作,需要重新启动Windows Server 2019。

根据互联网,代码应该工作。有人知道为什么没有吗?

我使用这个HttpContext扩展方法来读取请求正文,并将其缓存在上下文中,以备稍后在管道中需要时使用。

注意EnableBuffering周围的条件。也许在你的代码中加入这个条件会有帮助。

public static async Task<string> GetRequestBodyAsStringAsync(
this HttpContext httpContext)
{
if (httpContext.Items.TryGetValue("BodyAsString", out object? value))
return (string)value!;
if (!httpContext.Request.Body.CanSeek)
{
// We only do this if the stream isn't *already* rewindable,
// as EnableBuffering will create a new stream instance
// each time it's called
httpContext.Request.EnableBuffering();
}
httpContext.Request.Body.Position = 0;
StreamReader reader = new(httpContext.Request.Body, Encoding.UTF8);
string bodyAsString = await reader.ReadToEndAsync().ConfigureAwait(false);
httpContext.Request.Body.Position = 0;
httpContext.Items["BodyAsString"] = bodyAsString;
return bodyAsString;
}

编辑…

可能,你的问题也可能与你的控制器方法返回一个void而不是Task有关?

最后,我找到了我用于扩展方法的原始文章。有趣的是,如果您在模型绑定后第一次使用该扩展方法,那么它将不起作用(在我的项目中,我确实从中间件调用它)。

https://markb.uk/asp-net-core-read-raw-request-body-as-string.html

添加:

public class EnableRequestBodyBufferingMiddleware
{
private readonly RequestDelegate _next;
public EnableRequestBodyBufferingMiddleware(RequestDelegate next) =>
_next = next;
public async Task InvokeAsync(HttpContext context)
{
context.Request.EnableBuffering();
await _next(context);
}
}

app.UseMiddleware<EnableRequestBodyBufferingMiddleware>();

可能也有帮助。

最新更新