【问题标题】:In ASP.NET Core FromHeader is causing the Request.Body to be fully read在 ASP.NET Core FromHeader 中导致 Request.Body 被完全读取
【发布时间】:2021-03-31 01:32:06
【问题描述】:

在 ASP.Net Core 中,我有这个动作方法:

[HttpPost("things")]
[DisableFormValueModelBinding]
public async Task<IActionResult> UploadAsync()
{
    using StreamReader sr = new StreamReader(Request.Body);
    string body = await sr.ReadToEndAsync().ConfigureAwait(false);
    int bodyLength = body.Length;
    return Ok();
}

它工作得很好。正文是流式传输的,我可以全部阅读。但是,一旦我尝试获取标题:

[HttpPost("things")]
[DisableFormValueModelBinding]
public async Task<IActionResult> UploadAsync(
    [FromHeader(Name = "X-Test")] string test)
{
    using StreamReader sr = new StreamReader(Request.Body);
    string body = await sr.ReadToEndAsync().ConfigureAwait(false);
    int bodyLength = body.Length;
    return Ok();
}

正文已经在流的末尾,并且读取了零字节。显然我正在从一个标题中读取,这不应该影响请求正文。如果我将代码更改为:

[HttpPost("things")]
[DisableFormValueModelBinding]
public async Task<IActionResult> UploadAsync()
{
    string test = Request.Headers["X-Test"].First();
    using StreamReader sr = new StreamReader(Request.Body);
    string body = await sr.ReadToEndAsync().ConfigureAwait(false);
    int bodyLength = body.Length;
    return Ok();
}

动作又开始起作用了,我什至正在阅读标题。如果我切换回 FromHeader 它会再次失败。显然,FromHeader 正在内部做一些与请求正文混淆的事情。

使用 FromHeader 让 Swagger 继续工作对我来说很重要。如果没有 FromHeader,我无法在 Swagger 中指定标头值。

于是我开始搜索,发现了这个页面:

https://github.com/dotnet/aspnetcore/issues/18087

似乎其他人在使用 FromQuery 时遇到了类似的问题,有些人通过以下方式解决了这个问题:

结果: System.IO.IOException:Stream 意外结束,内容可能已被另一个组件读取。在 Microsoft.AspNetCore.WebUtilities.MultipartReaderStream.ReadAsync(Byte[] 缓冲区,Int32 偏移量,Int32 计数,CancellationToken cancelToken)

并且是“固定”的: [DisableFormValueModelBinding] 和 factory.RemoveType();

组装 Microsoft.AspNetCore.WebUtilities,版本=3.1.0.0 组装 Microsoft.AspNetCore.Mvc.Core,版本=3.1.0.0

...

仔细检查您的 DisableFormValueModelBindingAttribute 代码,确保它正在删除 FormFileValueProviderFactory。

我去尝试看看它是否有什么不同,但我在 NuGet 中看到的这些库的最新版本是 2.2.0 和 2.2.5,这是我安装的最新稳定版本。而且这些库中还不存在这种类型(FormFileValueProviderFactory)。使用 ILSpy 进行检查表明它确实不存在。 VS 确实显示我的目标框架是 .NET Core 3.1。

无论如何,我什至不确定这是否能解决我的问题。

有人对我可能出了什么问题有任何建议吗?

谢谢!

【问题讨论】:

  • 您的目标是什么确切的 ASP.NET Core 版本? 3.1 还是 2.2?检查您的csproj 文件。 FormFileValueProviderFactory 是在 ASP.NET Core 3.0 中引入的,是 Microsoft.AspNetCore.Mvc.Core 的一部分。如果您的目标框架是netcoreapp3.1,那么您应该能够在没有显式包引用的情况下使用FormFileValueProviderFactory,因为Microsoft.AspNetCore.Mvc.Core 是作为框架包的一部分提供的。由于 3.0 ASP.NET Core 不再作为 nuget 包提供,而是作为一个框架提供,它作为 SDK 的一部分。
  • 如果您在类库(.NET Core 或 .NET Standard)中编写代码,则必须将目标框架设置为 netcoreapp3.1 才能使用 ASP.NET Core 3.1 包。见this answer
  • 我可以在&lt;TargetFramework&gt;netcoreapp3.1&lt;/TargetFramework&gt; in .csproj 中读取我网站上的标题和正文
  • 是的,在我的 .csproj 中我也有:netcoreapp3.1。而且最新版本的 NuGet 是 2.2.5 (nuget.org/packages/Microsoft.AspNetCore.Mvc.Core) 并且没有 FormFileValueProviderFactory,虽然 MSFT 说它是在 3.0 中引入的,但它并不是我唯一可用的库:docs.microsoft.com/en-us/dotnet/api/…。我正在 ILSpy 中查看它以确认,并且无论如何尝试在 VS 中构建它也失败了。

标签: c# asp.net-core asp.net-core-mvc asp.net-core-webapi


【解决方案1】:

我已经确认如果我在DisableFormValueModelBindingAttribute 中的ValueProviderFactories 中搜索FormFileValueProviderFactory,我只需执行Where(p =&gt; p.GetType().Name == "FormFileValueProviderFactory").FirstOrDefault() 即可找到它。然后,如果我将其从工厂列表中删除,一切正常。

所以现在的问题变成了为什么我不能引用该类型。由于我已拉出类型,因此我可以查看被引用的程序集,它是@​​987654325@。这意味着它甚至根本没有使用 NuGet,而是使用了这个程序集。因此,当我发现为什么以这种方式设置这个项目时,我开始删除旧的和不必要的 NuGet 引用。帮助程序库中有一些 ASP.NET Core MVC 实用程序,包括 DisableFormValueModelBindingAttribute。这个库当前配置为netstandard2.1,这就是为什么不能引用 ASP.NET Core 的东西。

要解决此问题,我只需将目标框架更改为 netcoreapp3.1 并将其添加到引用 ASP.NET Core:

<ItemGroup>
  <FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

现在一切正常。

【讨论】:

    猜你喜欢
    • 2022-01-09
    • 1970-01-01
    • 2018-01-29
    • 2013-08-30
    • 1970-01-01
    • 1970-01-01
    • 2021-03-29
    • 2016-11-19
    • 2021-11-16
    相关资源
    最近更新 更多