UFO ET IT

Request.Content.ReadAsMultipartAsync가 반환되지 않음

ufoet 2021. 1. 13. 07:28
반응형

Request.Content.ReadAsMultipartAsync가 반환되지 않음


ASP.NET Web Api를 사용하여 작성된 시스템 용 API가 있으며 이미지를 업로드 할 수 있도록 확장하려고합니다. 몇 가지 인터넷 검색을 수행했으며 MultpartMemoryStreamProvider 및 일부 비동기 메서드를 사용하여 파일을 수락하는 권장 방법이 방법을 찾았지만 ReadAsMultipartAsync에 대한 대기가 반환되지 않습니다.

다음은 코드입니다.

[HttpPost]
public async Task<HttpResponseMessage> LowResImage(int id)
{
    if (!Request.Content.IsMimeMultipartContent())
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }

    var provider = new MultipartMemoryStreamProvider();

    try
    {
        await Request.Content.ReadAsMultipartAsync(provider);

        foreach (var item in provider.Contents)
        {
            if (item.Headers.ContentDisposition.FileName != null)
            {

            }
        }

        return Request.CreateResponse(HttpStatusCode.OK);
    }
    catch (System.Exception e)
    {
        return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
    }
}

다음 단계까지 진행할 수 있습니다.

await Request.Content.ReadAsMultipartAsync(provider);

어느 시점에서는 완료되지 않습니다.

my await가 돌아 오지 않는 이유는 무엇입니까?

최신 정보

curl을 사용하여이 작업에 POST를 시도하고 있는데 명령은 다음과 같습니다.

C:\cURL>curl -i -F filedata=@C:\LowResExample.jpg http://localhost:8000/Api/Photos/89/LowResImage

또한 다음 html을 사용하여 작업에 게시하려고 시도했으며 동일한 일이 발생합니다.

<form method="POST" action="http://localhost:8000/Api/Photos/89/LowResImage" enctype="multipart/form-data">
    <input type="file" name="fileupload"/>
    <input type="submit" name="submit"/>
</form>

.NET 4.0에서 비슷한 문제가 발생했습니다 (비동기 / 대기 없음). 디버거의 스레드 스택을 사용하여 ReadAsMultipartAsync가 동일한 스레드에서 작업을 시작했음을 알 수 있으므로 교착 상태가됩니다. 나는 다음과 같이했다.

IEnumerable<HttpContent> parts = null;
Task.Factory
    .StartNew(() => parts = Request.Content.ReadAsMultipartAsync().Result.Contents,
        CancellationToken.None,
        TaskCreationOptions.LongRunning, // guarantees separate thread
        TaskScheduler.Default)
    .Wait();

TaskCreationOptions.LongRunning 매개 변수가 없으면 호출이 동일한 스레드에서 작업을 계속 시작하기 때문에 중요했습니다. 다음 의사 코드와 같은 것을 사용하여 C # 5.0에서 작동하는지 확인할 수 있습니다.

await TaskEx.Run(async() => await Request.Content.ReadAsMultipartAsync(provider))

모든 최신 4.5.2 프레임 워크에서 동일한 문제가 발생했습니다.

내 API 메서드는 멀티 파트 콘텐츠가 포함 된 POST 요청을 사용하여 업로드 된 하나 이상의 파일을 허용합니다. 작은 파일에서는 잘 작동했지만 큰 파일에서는 ReadAsMultipartAsync()함수가 완료되지 않았기 때문에 내 방법이 영원히 중단 되었습니다.

나에게 도움이 무엇 : 사용하여 async제어 방법 및 await(가)에 대한 ReadAsMultipartAsync()완료하는 대신 동기 제어 방식의 작업 결과를 받고.

그래서 이것은 작동하지 않았습니다.

[HttpPost]
public IHttpActionResult PostFiles()
{
    return Ok
    (
        Request.Content.ReadAsMultipartAsync().Result

        .Contents
        .Select(content => ProcessSingleContent(content))
    );
}

private string ProcessSingleContent(HttpContent content)
{
    return SomeLogic(content.ReadAsByteArrayAsync().Result);
}

그리고 이것은 효과가 있습니다.

[HttpPost]
public async Task<IHttpActionResult> PostFiles()
{
    return Ok
    (
        await Task.WhenAll
        (
            (await Request.Content.ReadAsMultipartAsync())

            .Contents
            .Select(async content => await ProcessSingleContentAsync(content))  
        )
    );
}

private async Task<string> ProcessSingleContentAsync(HttpContent content)
{
    return SomeLogic(await content.ReadAsByteArrayAsync());
}

여기서 SomeLogic(처리의 종류 일 수있다) 문자열을 바이너리 컨텐츠를 취하고 제조 단지 동기 함수이다.

업데이트 마지막으로이 기사에서 설명을 찾았습니다 : https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

The root cause of this deadlock is due to the way await handles contexts. By default, when an incomplete Task is awaited, the current “context” is captured and used to resume the method when the Task completes. This “context” is the current SynchronizationContext unless it’s null, in which case it’s the current TaskScheduler. GUI and ASP.NET applications have a SynchronizationContext that permits only one chunk of code to run at a time. When the await completes, it attempts to execute the remainder of the async method within the captured context. But that context already has a thread in it, which is (synchronously) waiting for the async method to complete. They’re each waiting for the other, causing a deadlock.

So, basically, the “Async all the way” guideline has a reason behind it, and this is a good example.


With help of another answer on stackoverflow and a blog post about targetFramework, I've found that updating to 4.5 and adding/updating the following in your web.config fixes this issue:

<system.web>
    <compilation debug="true" targetFramework="4.5"/>
</system.web>
<appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>

I have a working .Net MVC WebAPi project with the following Post method which seems to work well. It's very similar to what you have already so this should be helpful.

    [System.Web.Http.AcceptVerbs("Post")]
    [System.Web.Http.HttpPost]
    public Task<HttpResponseMessage> Post()
    {
        // Check if the request contains multipart/form-data.
        if (!Request.Content.IsMimeMultipartContent())
        {
            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
        }
        string fileSaveLocation = @"c:\SaveYourFile\Here\XXX";
        CustomMultipartFormDataStreamProvider provider = new CustomMultipartFormDataStreamProvider(fileSaveLocation);
        Task<HttpResponseMessage> task = Request.Content.ReadAsMultipartAsync(provider).ContinueWith<HttpResponseMessage>(t =>
            {
                if (t.IsFaulted || t.IsCanceled)
                {
                    Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
                }
                foreach (MultipartFileData file in provider.FileData)
                {
                    //Do Work Here
                }
                return Request.CreateResponse(HttpStatusCode.OK);
            }
        );
        return task;
    }

I had the same. My solution

public List<string> UploadFiles(HttpFileCollection fileCollection)
    {
        var uploadsDirectoryPath = HttpContext.Current.Server.MapPath("~/Uploads");
        if (!Directory.Exists(uploadsDirectoryPath))
            Directory.CreateDirectory(uploadsDirectoryPath);

        var filePaths = new List<string>();

        for (var index = 0; index < fileCollection.Count; index++)
        {
            var path = Path.Combine(uploadsDirectoryPath, Guid.NewGuid().ToString());
            fileCollection[index].SaveAs(path);
            filePaths.Add(path);
        }

        return filePaths;
    }

and invoking

if (!Request.Content.IsMimeMultipartContent())
{
    throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}

var filePaths = _formsService.UploadFiles(HttpContext.Current.Request.Files);

ReferenceURL : https://stackoverflow.com/questions/15201255/request-content-readasmultipartasync-never-returns

반응형