>source

저는 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 로그에는 요청도 응답 항목도 없습니다. 추적 로그에 있습니다.

이것은 IIS 호스팅 웹 응용 프로그램에서 발생합니까, 아니면 로컬 개발 시스템에서 발생합니까? 다른 시스템이나 다른 네트워크에서 문제를 재현할 수 있습니까(즉, 웹 서버로 가는 도중에 연결을 끊는 것이 없는지 확인하기 위해 통신 채널을 분리). 또한 IIS 로그를 확인하십시오.

ardila2022-02-14 19:57:13

@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
  • 이전 flutter : 플러터에 컨테이너를 사용하여 아래 이미지와 같이 곡선/오목을 만드시겠습니까?
  • 다음 Git: 재생을 위한 첫 번째 되감기 헤드