c# - 大小超过64KB的请求无法完成(Asp.Net Core Web API)

标签 c# rest image-uploading asp.net-core-webapi .net-4.6.1

我正在使用Visual Studio 2017(15.6.5)中的Asp.Net Core 2.0 Web API技术(完整的.Net Framework 4.6.1)开发REST Web服务。

我的问题

每当我发送超过64 KB的发布请求时,它都会挂起,并且永远不会完成。例如,一个大小为68'259字节的发布请求失败,而一个大小为63'534字节的发布请求确实完成了而没有任何问题。

当我尝试上传图像(使用MultipartFormDataContent)时,问题首次开始出现,但请求的内容无关紧要。我还尝试将图像作为字节数组和作为转换后的Base64字符串发送到另一个对象实例内的属性中。

到底发生了什么

使用Fiddler捕获流量时,请求永远不会完成。它永远不会收到响应。





甚至不会调用controller方法,因为不会碰到其中的任何断点。但是,我们的自定义中间件的Invoke方法被调用,尽管它从未运行过await this._next.Invoke(context)行。

public class VersioningMiddleware
{
    private readonly RequestDelegate _next;

    public VersioningMiddleware(RequestDelegate next)
    {
        this._next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        ...

        await this._next.Invoke(context);
    }
    ...
}


更多信息

我用this tutorial上传图像。

尝试弄清楚(无济于事)为什么Web服务从未返回响应后,我下载了示例解决方案以查看该解决方案是否仍然有效。它确实做到了,尽管它使用.Net Standard而非完整的.Net Framework,所以我在该解决方案中使用完整的.Net Framework创建了一个新的Web服务项目,复制了整个控制器,并将目标平台更改为x86以匹配我实际的Web服务的配置(我们仍然必须查询MS Access数据库,这就是为什么我坚持使用32位应用程序的原因)。
这个示例Web服务的新版本还可以像上传上64 KB以上的图像一样吸引人。

这对我来说没有太大意义,因为我看不到任何重大差异。

发送请求的应用代码(为清楚起见,在某些部分中缩写):

public async Task UploadImageAsync(byte[] imageData, string fileName, object objectParameter, CancellationToken cancellationToken, params string[] pathComponents)
{
    ...

    using (MemoryStream stream = new MemoryStream(imageData))
    {
        using (HttpContent fileStreamContent = new StreamContent(stream))
        {
            fileStreamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "file", FileName = fileName };
            fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            using (MultipartFormDataContent formData = new MultipartFormDataContent())
            {
                formData.Add(fileStreamContent);
                string apiPath = String.Join(Globals.PathSeparator, pathComponents);
                if (objectParameter != null)
                {
                    apiPath = apiPath + "?" + objectParameter.ToQueryString();
                }
                await this.SendPostAsync(apiPath, formData, cancellationToken).ConfigureAwait(false))
            }
        }
    }
} 

private Task<HttpResponseMessage> SendPostAsync(string path, HttpContent content, CancellationToken cancellationToken)
{
    return this.SendRequestAsync(HttpAction.Post, path, content, cancellationToken);
} 

private async Task<HttpResponseMessage> SendRequestAsync(HttpAction action, string path, HttpContent content, CancellationToken cancellationToken)
{
    ...
    switch (action)
    {
        ...
        case HttpAction.Post:
        response = await this._client.PostAsync(path, content, cancellationToken).ConfigureAwait(false);
        break;
        ...
    }
...
return response;
}


Web服务控制器代码(也缩写):

[Route("api/[controller]")]
public class DocumentsController : ControllerBase
{ 
    private readonly IDocumentsRepository _documents; 
    ...

    public DocumentsController(IDocumentsRepository documents, ...)
    {
        this._documents = documents;
        ...
    }
    ...

    [HttpPost(nameof(SaveImage))]
    [Authorize(JwtBearerDefaults.AuthenticationScheme)]
    public IActionResult SaveImage(IFormFile file, [FromQuery]ServiceReportIdentification documentInfo)
    {
        this._documents.SaveImage(file, documentInfo);
        return this.CreatedAtAction(nameof(SaveImage), file);
    }
    ...
}


请求大小限制

IIS的默认请求大小限制应为4 MB,而我尝试上传的大多数图像都小于1 MB,因此这不是问题。但是,我仍然尝试手动设置所有大小限制,以查看是否可以覆盖该隐藏的64 KB大小限制。没有骰子。

我什至从示例解决方案的.vs \ config \ applicationhost.config文件中复制了httpCompression标记,这是与我的实际Web服务解决方案唯一的区别。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.web>
    <httpRuntime maxRequestLength="10240" />
  </system.web>
  <system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="10485760" />
      </requestFiltering>
    </security>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" startupTimeLimit="3600" requestTimeout="23:00:00" />
    <httpCompression>
        <dynamicCompression>
            <add mimeType="text/event-stream" enabled="false" />
        </dynamicCompression>
    </httpCompression>
  </system.webServer>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="ServicePlusApi" maxReceivedMessageSize="10485760" />
            </wsHttpBinding>
        </bindings>
    </system.serviceModel>
</configuration>


一些背景

当我创建Web服务解决方案时,Asp.Net Core尚未达到2.0版,这就是为什么Web API项目中仍然存在web.config文件的原因。从2.0(或至少是我的假设)开始,web.config文件不再存在。而是将默认配置存放在.vs \ config \ applicationhost.config文件中。

因此,我创建了一个新的解决方案和Web API项目,并从我的Web服务中添加了代码,并添加了引用所需的其他项目,实质上是使用相同的代码库但使用最新的项目结构/定义来重新创建整个解决方案。

尽管如此,它还是不飞。



我不知道是什么原因导致了64 KB的奇怪请求大小限制,甚至没有返回错误,IIS日志中也没有任何请求记录。它只是吞没了请求,从不提供任何形式的响应(除了客户端超时)。

有谁知道这可能是什么原因?我已经在互联网上搜寻了很长一段时间,除了那些手动大小限制替代(在这种情况下不起作用)之外,我发现没有任何帮助。

编辑:

上述行为在使用Visual Studio的IIS Express的调试模式下在开发计算机上本地发生。当Web服务以发布模式发布并由另一台计算机上的标准IIS托管时,同样适用。

更新

在IIS跟踪日志中搜索更多线索后,我发现了以下事件:

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
 <System>
  ...
 </System>
 <EventData>
  <Data Name="ContextId">{8000006B-0006-FF00-B63F-84710C7967BB}</Data>
  <Data Name="ModuleName">AspNetCoreModule</Data>
  <Data Name="Notification">128</Data>
  <Data Name="HttpStatus">400</Data>
  <Data Name="HttpReason">Bad Request</Data>
  <Data Name="HttpSubStatus">0</Data>
  <Data Name="ErrorCode">2147952454</Data>
  <Data Name="ConfigExceptionInfo"></Data>
 </EventData>
 <RenderingInfo Culture="de-CH">
  <Opcode>MODULE_SET_RESPONSE_ERROR_STATUS</Opcode>
  <Keywords>
   <Keyword>RequestNotifications</Keyword>
  </Keywords>
  <freb:Description Data="Notification">EXECUTE_REQUEST_HANDLER</freb:Description>
  <freb:Description Data="ErrorCode">Eine vorhandene Verbindung wurde vom Remotehost geschlossen.
 (0x80072746)</freb:Description>
 </RenderingInfo>
 ...
</Event>


错误说明是德语,并指出:“现有连接已被远程主机关闭。”

再往下看,我发现一些响应数据,其中包含错误页面的缓冲数据(由于Web服务的性质而从未显示),其中包含以下错误文本:“由于以下原因,服务器无法理解该请求:语法错误。”

奇怪的是,普通的IIS日志中没有请求,也没有响应条目。只是在跟踪日志中。

最佳答案

经过消除过程后,我发现了此请求限制的罪魁祸首。

System.Windows.Forms.RichTextBox


我们需要它从RTF文本中提取纯文本,因为我们的Xamarin应用程序无法处理RTF文本。事实证明,ASP.Net Core Web API Web服务不喜欢WinForms组件。

当删除所述RichTextBox的实例化时,图像上载就像它的魅力一样。

经验教训:永远不要在Web服务中使用WinForms组件。



但是,我仍然不知道为什么使用RichTextBox具有这种特定效果(超过64 KB的请求不会得到处理)。

它会触发隐藏的兼容模式吗?是因为缺少UI线程吗?

如果有人知道这一点,请告诉我。

关于c# - 大小超过64KB的请求无法完成(Asp.Net Core Web API),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49672813/

相关文章:

ruby-on-rails - 向 Grape 实体添加常量属性

java - 创建新资源时出现 400 错误的 Dropwizard 示例

api - 经典 API key 与 REST API 凭证共存的 Paypal 可能性

jquery - grails:无需页面刷新即可上传图片

c# - 使用或不使用 new 在 C# 中创建对象

c# - 如何控制访问控制?

android - 如何将SD卡中的图像上传到服务器中的文件夹

javascript - 将文件类型限制为多个文件 uploader

c# - 单元测试异步事件处理程序

c# - 使用 SemanticZoom 显示按字母顺序排列的标题,就像在“开始”菜单上一样