Подтвердить что ты не робот

WebAPI не может анализировать сообщение multipart/form-data

Я пытаюсь принять сообщение от клиента (приложение iOS), и мой код продолжает терпеть неудачу при чтении потока. Говорит, что сообщение не завершено. Я пытался заставить эту работу часами, кажется, что-то не так в моем формате сообщения или что-то в этом роде. Все, что я пытаюсь сделать, это прочитать строку, но разработчик, с которым я работаю, который выполняет роль iOS, знает, как отправлять multipart/form-data, а не контент-тип json.

Вот точная ошибка:

Неожиданный конец многопоточного потока MIME. Сообщение MIME multipart не является полным. "

Здесь не удается: await Request.Content.ReadAsMultipartAsync(provider);

Headers:

POST http://localhost:8603/api/login HTTP/1.1
Host: localhost:8603
Accept-Encoding: gzip,deflate
Content-Type: multipart/form-data; boundary=------------nx-oauth216807
Content-Length: 364
Accept-Language: en-us
Accept: */*
Connection: keep-alive

Тело

--------------nx-oauth216807
Content-Disposition: form-data; name="token"

CAAH5su8bZC1IBAC3Qk4aztKzisZCd2Muc3no4BqVUycnZAFSKuleRU7V9uZCbc8DZCedYQTIFKwJbVZCANJCs4ZCZA654PgA22Nei9KiIMLsGbZBaNQugouuLNafNqIOTs9wDvD61ZA6WSTd73AVtFp9tQ1PmFGz601apUGHSimYZCjLfGBo40EBQ5z6eSMNiFeSylym1pK4PCvI17fXCmOcRix4cs96EBl8ZA1opGKVuWizOsS0WZCMiVGvT
--------------nx-oauth216807--

Вот код WebAPI:

    public async Task<HttpResponseMessage> PostFormData()
    {
        // Check if the request contains multipart/form-data.
        if (!Request.Content.IsMimeMultipartContent())
        {
            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
        }
        try
        {
        string root = HttpContext.Current.Server.MapPath("~/App_Data");
        var provider = new MultipartFormDataStreamProvider(root);

        // Read the form data and return an async task.
        await Request.Content.ReadAsMultipartAsync(provider);

        // This illustrates how to get the file names.
        foreach (MultipartFileData file in provider.FileData)
        {
            Trace.WriteLine(file.Headers.ContentDisposition.FileName);
            Trace.WriteLine("Server file path: " + file.LocalFileName);
        }
        return Request.CreateResponse(HttpStatusCode.OK);

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

Ответ 1

В моем приложении периодически возникала и эта ошибка. Обновление до WEB API 2.1 ничего не делало, и сообщение об исключении совершенно бесполезно.

Я думаю, что на самом деле это происходит, но это задыхается от больших файлов. Увеличение моих максимальных пределов запроса в web.config, похоже, исправило это.

<system.web>
    <httpRuntime maxRequestLength="30000" />
</system.web>

<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="30000" />
      </requestFiltering>
    </security>
</system.webServer>

(Это устанавливает потолок в 30 мегабайт. Установите его на все, что вам нужно. Подробнее здесь)

Ответ 2

Я тоже столкнулся с этой ошибкой. InnerException Cannot access a disposed object. Это означает, что что-то читает ваш поток перед вашим вызовом ReadAsMultipartAsync.
Где-то перед этим вызовом Request.Content.ReadAsMultipartAsync(provider) вы можете позвонить Request.Content.LoadIntoBufferAsync().Wait(), который загрузит этот поток в буфер и позволит вам читать его более одного раза.
Это не оптимальное решение, но оно работает.

Ответ 3

Я оставляю это здесь, так как мне потребовалось некоторое время, пробовав другие обходные пути, пока я не столкнулся с следующим полезным ответом, и некоторые люди, имеющие эту проблему, могут оказаться в этом сообщении.

A\r\n необходимо добавить в конец потока содержимого запроса.

Вместо использования этой строки для чтения данных:

await Request.Content.ReadAsMultipartAsync(provider);

Вам нужно будет:

  • Загрузка потока запросов в память

  • добавить строку \r\n, которая требуется

  • создать содержимое потока из содержимого памяти

  • вручную добавить заголовки запросов в контент потока

  • Наконец, используйте это вместо:

    streamContent.ReadAsMultipartAsync(provider); 
    

Проверьте ответ Landuber Kassa на полный код: ASP.NET Web API, неожиданный конец многочастного потока MIME при загрузке из Flex FileReference

Ответ 4

Просто модификация для ответа Шоу Левина на тот случай, если кто-то захочет его использовать.

boundary = value.Substring(0, value.IndexOf("\r\n")); найдет первое появление CRLF, вы должны изменить его на boundary = value.Substring(0, value.LastIndexOf("\r\n"));, чтобы он выглядел последним. В противном случае, если контент содержит CRLF где-то посередине, вы потеряете часть данных в запросе.

Ответ 5

Были похожие сообщения об ошибках, для некоторых из них работало следующее: упомянуть атрибут Id = ", name=" "для управления загрузкой файла html, благодаря загрузке WebAPI ошибка. Ожидаемый конец многоточечного потока MIME. Сообщение MIME не завершено

Но в моем случае это не разрешилось с помощью простого простого тэка:(

Ответ 6

Я бы не рекомендовал этот ответ - надеюсь, теперь есть лучший способ.

Кто-то спросил, так вот мой пользовательский парсер, который отлично работает:

Граница исходит отсюда:

        string value;
        using (var reader = new StreamReader(tempStream, Encoding.UTF8))
        {
            value = reader.ReadToEnd();
            // Do something with the value
        }

        boundary = value.Substring(0, value.IndexOf("\r\n"));

И затем мы проанализируем содержимое запроса здесь:

   public Dictionary<string, BodyContent> ParseContent(string content)
    {
        string[] list = content.Split(new string[] { boundary }, StringSplitOptions.RemoveEmptyEntries);
        string name="", val="";
        Dictionary<string, BodyContent> temp = new Dictionary<string, BodyContent>();
        foreach (String s in list)
        {
            if (s == "--" || s == "--\r\n")
            {
                //Do nothing.
            }
            else
            {
                string[] token = s.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
                val = "";
                name = "";
                foreach (string x in token)
                {

                    if(x.StartsWith("Content-Disposition"))
                    {
                        //Name
                        name = x.Substring(x.IndexOf("name=")+5, x.Length - x.IndexOf("name=")-5);
                        name = name.Replace(@"\","");
                        name = name.Replace("\"","");
                    }
                    if (x.StartsWith("--"))
                    {
                        break;
                    }
                    if (!x.StartsWith("--") && !x.StartsWith("Content-Disposition"))
                    {
                        val = x;
                    }

                }
                if (name.Length > 0)
                {
                    BodyContent b = new BodyContent();
                    b.content = name;
                    if (val.Length == 0)
                    {
                        b.value = "";
                    }
                    else
                    {
                        b.value = val;
                    }
                    temp.Add(name, b);
                }
            }

        }
        return temp;        
    }