我正在使用Visual Studio 2017(15.6.5)中的Asp.Net Core 2.0 Web API技术(完整的.Net Framework 4.6.1)开发REST Web服务。
每当我发送超过64 KB的发布请求时,它都会挂起并且永远不会完成。例如,大小为68'259字节的post请求失败,而大小为63'534字节的post请求确实完成没有任何问题。
当我尝试上传图片(使用MultipartFormDataContent
)时问题首次出现时,请求的内容无关紧要。我还尝试将图像作为字节数组和转换后的Base64字符串发送到另一个对象实例中的属性中。
使用Fiddler捕获流量时,请求永远不会完成。它永远不会收到回应。
控制器方法永远不会被调用,因为它内部没有任何断点。但是,我们调用自定义中间件的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上传图片。
在试图找出(无效)为什么webservice永远不会返回响应时,我下载了示例解决方案,看看是否有效。虽然它使用了.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日志中还没有请求,也没有响应条目。只是在跟踪日志中。
答案 0 :(得分:2)
在完成淘汰过程后,我发现了这个请求限制的罪魁祸首。
System.Windows.Forms.RichTextBox
我们需要它从RTF文本中提取纯文本,因为我们的Xamarin应用程序无法处理RTF文本。事实证明,ASP.Net Core Web API Web服务不喜欢WinForms组件。
当删除所述RichTextBox的实例化时,图像上传就像魅力一样,就像它应该的那样。
获得的经验教训:永远不要在Web服务中使用WinForms组件。
但是,我仍然不知道为什么使用RichTextBox会产生这种特殊效果(超过64 KB的请求不会被处理)。
是否会触发隐藏的兼容模式?是因为缺少UI线程吗?
如果有人知道,请告诉我。