저는 Visual Studio 2017(15.6.5) 내에서 Asp.Net Core 2.0 Web API 기술(전체 .Net Framework 4.6.1)을 사용하여 REST 웹 서비스를 개발 중입니다.
내 문제
64KB를 초과하는 게시물 요청을 보낼 때마다 중단되고 완료되지 않습니다. 예를 들어 크기가 68'259바이트인 게시 요청은 실패하지만 크기가 63,534바이트인 게시 요청은 문제 없이 완료됩니다.
이미지를 업로드하려고 할 때 문제가 처음 나타나기 시작했지만(멀티파트폼데이터컨텐츠
), 요청 내용은 중요하지 않습니다. 또한 이미지를 바이트 배열과 다른 개체 인스턴스 내의 속성 내부에 변환된 Base64 문자열로 보내려고 했습니다.
정확히 무슨 일이 일어나는지
Fiddler로 트래픽을 캡처할 때 요청이 완료되지 않습니다. 응답을 받지 않습니다.
컨트롤러 메서드는 호출되지 않습니다. 그 안에 중단점이 적중하지 않기 때문입니다. 그러나 사용자 정의 미들웨어의 Invoke 메소드가 호출되고 있지만 라인을 지나치지는 않습니다.이것을 기다리십시오._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);
}
...
}
추가 정보
이미지 업로드에 사용했습니다.
웹 서비스가 응답을 반환하지 않는 이유를 알아내려고 했을 때 (소용이 없었음), 예제 솔루션을 다운로드하여 해당 솔루션이 작동하는지 확인했습니다. 그리고 그것은 전체 .Net Framework 대신 .Net Standard를 사용하기는 하지만 전체 .Net Framework를 사용하여 해당 솔루션 내에서 새 웹 서비스 프로젝트를 만들고 전체 컨트롤러에 복사하고 대상 플랫폼도 일치하도록 x86으로 변경했습니다. 실제 웹 서비스에 대한 구성(여전히 MS Access 데이터베이스를 쿼리해야 하기 때문에 32비트 응용 프로그램을 사용하고 있습니다). 이 새 버전의 예제 웹 서비스는 64KB보다 큰 이미지를 업로드하는 데에도 유용했습니다.
큰 차이를 볼 수 없었기 때문에 이것은 나에게 별로 의미가 없었습니다.
요청을 보내는 앱 code(명확성을 위해 일부 축약됨):
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;
}
웹 서비스 컨트롤러 code(약어):
[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 요청 크기 제한은 4MB여야 하고 업로드하려는 대부분의 이미지는 1MB 미만이므로 문제가 되지 않습니다. 그러나 숨겨진 64KB 크기 제한을 무시할 수 있는지 확인하기 위해 찾을 수 있는 모든 크기 제한을 수동으로 설정하려고 시도했습니다. 주사위가 없습니다.
나도 복사했어http압축
예제 솔루션의 .vs\config\applicationhost.config 파일에서 태그를 가져옵니다. 이것이 실제 웹 서비스 솔루션을 구성하는 것과 유일한 차이점이었습니다.
<?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>
일부 배경
웹 서비스 솔루션을 만들 때 Asp.Net Core는 아직 버전 2.0에 도달하지 않았기 때문에 Web API 프로젝트에 여전히 web.config 파일이 있습니다. 2.0(또는 최소한 내 가정)부터 web.config 파일은 더 이상 존재하지 않습니다. 대신 기본 구성이 .vs\config\applicationhost.config 파일에 저장됩니다.
이러한 이유로 웹 서비스의 code에 추가한 새로운 솔루션과 Web API 프로젝트를 만들었으며 참조에 필요한 추가 프로젝트도 추가하여 기본적으로 동일한 code베이스를 사용하지만 최신 프로젝트 구조/정의를 사용하여 전체 솔루션을 다시 만듭니다.
그래도 이것은 날지 않았습니다.
저는 오류를 반환하지 않는 이상한 64KB 요청 크기 제한의 원인이 무엇인지 전혀 알 수 없으며 IIS 로그에 요청 기록도 없습니다. 그것은 요청을 삼키고 어떤 종류의 응답도 제공하지 않습니다(클라이언트 측 시간 초과 제외).
이 문제의 원인이 무엇인지 아는 사람이 있습니까? 나는 꽤 오랫동안 인터넷을 샅샅이 뒤졌고 이 경우에는 작동하지 않는 수동 크기 제한 무시 외에 도움이 되는 것을 찾지 못했습니다.
수정:
위에서 설명한 동작은 Visual Studio의 IIS Express를 사용하는 디버그 모드의 개발 머신에서 로컬로 발생합니다. 웹 서비스가 릴리스 모드로 게시되고 다른 시스템의 표준 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>
오류 설명은 독일어로 되어 있으며 "원격 호스트가 기존 연결을 닫았습니다."
조금 더 내려가면 오류 페이지에 대한 버퍼 데이터(웹 서비스의 특성으로 인해 표시되지 않음)가 포함된 응답 데이터를 찾았습니다. 여기에는 "요청을 이해할 수 없습니다. 잘못된 구문으로 인해 서버에 오류가 발생했습니다."
이상하게도 일반 IIS 로그에는 요청도 응답 항목도 없습니다. 추적 로그에 있습니다.
@ardila 여기에 설명된 모든 것은 디버그 모드의 개발 머신에서 로컬로 발생합니다. 웹 서비스를 표준 IIS에서 호스팅하는 다른 시스템에 게시할 때도 마찬가지입니다. 요청이 그렇게 멀리 가지 않아 전혀 기록되지 않기 때문에 IIS 로그는 불행히도 도움이 되지 않습니다.
Vyzzuvazzadth2022-02-14 19:57:13@ardila 도움이 될 수 있는 추적 로그에서 무언가를 찾았습니다(내 질문의 업데이트 섹션 참조).
Vyzzuvazzadth2022-02-14 19:57:13- 답변 # 1
파일 데이터베이스 유형이 LONGBLOB 형식이어야 합니다.
추가 지원 정보를 통해 답변을 개선할 수 있습니다. 다른 사람들이 귀하의 답변이 올바른지 확인할 수 있도록 인용 또는 문서와 같은 추가 세부 정보를 추가하려면 편집하십시오. 도움말 센터에서 좋은 답변을 작성하는 방법에 대한 자세한 정보를 찾을 수 있습니다.
Community2022-02-15 06:41:46 - 답변 # 2
삭제 과정을 거친 후 이 요청 제한의 원인을 찾았습니다.
System.Windows.Forms.RichTextBox
Xamarin 앱이 RTF 텍스트를 처리할 수 없기 때문에 RTF 텍스트에서 일반 텍스트를 추출하는 데 필요했습니다. ASP.Net Core Web API 웹 서비스가 WinForms 구성 요소를 좋아하지 않는 것으로 나타났습니다.
해당 RichTextBox의 인스턴스화를 제거하면 이미지 업로드가 예상대로 매력처럼 작동합니다.
교훈: 웹 서비스 내에서 WinForms 구성 요소를 사용하지 마십시오.
그러나 RichTextBox를 사용하면 왜 이러한 특정 효과가 있는지 아직 모르겠습니다(64KB를 초과하는 요청은 처리되지 않음).
숨겨진 호환성 모드를 트리거합니까? 누락된 UI 스레드 때문인가요?
이것을 아시는 분은 알려주세요.
별도의 질문으로 게시하십시오. 완전히 다른 질문이며 이 질문에는 원래 질문을 크게 변경하지 않고 대답할 수 있을 만큼 UI에 대한 정보가 충분하지 않습니다.
ardila2022-02-14 20:11:37
이것은 IIS 호스팅 웹 응용 프로그램에서 발생합니까, 아니면 로컬 개발 시스템에서 발생합니까? 다른 시스템이나 다른 네트워크에서 문제를 재현할 수 있습니까(즉, 웹 서버로 가는 도중에 연결을 끊는 것이 없는지 확인하기 위해 통신 채널을 분리). 또한 IIS 로그를 확인하십시오.
ardila2022-02-14 19:57:13