Как загрузить большие (> 25 МБ) файлы в веб-службу?

У меня есть веб-служба, которая принимает byte[] и сохраняет его.

Это отлично работает для «небольших» файлов, но как только я достигну определенного размера, веб-служба дает сбой и возвращает «Запрос не выполнен со статусом HTTP 404: не найден».

Судя по тому, что я видел, это параметр IIS, который ограничивает размер файла, который можно опубликовать (для предотвращения атак типа «отказ в обслуживании»). Я пытался увеличить этот параметр, но у меня возникли проблемы с определением того, какой параметр и где/как его установить. Я использую IIS7, а веб-сервис выполняется в .net(asmx).

В web.config веб-службы я добавил следующее (что, казалось, увеличило размер файла, который может быть принят, но не полностью до этого размера настройки)

  <system.web>
     <httpRuntime executionTimeout="999999" maxRequestLength="2097151" />
     ...
  </system.web>

Любые предложения о том, где (и как) увеличить размер файла, который веб-сервис будет принят с благодарностью.


person ChrisHDog    schedule 15.06.2009    source источник
comment
Что касается WCF/FTP/WS-Attachment/DIME: отличные предложения и несколько интересных материалов для чтения. Это, вероятно, типы долгосрочных решений, которые я в конечном итоге буду использовать. Однако, если бы было какое-то краткосрочное решение для изменения размера загрузки в IIS7, это было бы превосходно. Спасибо.   -  person ChrisHDog    schedule 16.06.2009


Ответы (8)


В дополнение к httpRuntime/maxRequestLength, упомянутому в вопросе, похоже, что есть дополнительный элемент, который можно добавить в файл web.config веб-службы, чтобы разрешить передачу больших файлов.

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

Похоже, это позволяет загружать большие файлы через веб-сервисы.

person ChrisHDog    schedule 30.06.2009
comment
Просто примечание по этому поводу: указание на то, что вам не хватает этого параметра, - это когда вы получаете 404 от службы WCF, но в трассировке WCF нет сообщения об ошибке (да, очень полезно, я знаю - спасибо WCF). Рад, что ты нашел этого Криса, ты спас меня от лишних часов. - person Andy Britcliffe; 07.10.2009
comment
Да, эта дополнительная настройка потратила впустую много часов моего дня сегодня. Я не понимал, что с IIS7 вам нужно указать самый большой размер файла в ДВА местах в вашем файле web.config. Но да, с этой настройкой maxAllowedContentLength я наконец-то смог загружать файлы размером 31 МБ. - person Mike Gledhill; 26.08.2011
comment
@AndyBritcliffe Спасибо, WCF. Мне кажется, что в этом случае 404 исходит от самого IIS, поэтому WCF, вероятно, даже не слышал об этом событии, и поэтому у него было мало шансов что-либо зарегистрировать. Перефразируйте «Спасибо Microsoft», и критика остается в силе. :) - person The Dag; 14.11.2011
comment
Еще один голос благодарности, это ломало мне голову в течение часов. - person ChrisA; 31.07.2013

Вы должны иметь в виду, что веб-службы изначально не предназначены для передачи файлов. Любой специально разработанный протокол передачи файлов, скорее всего, будет работать лучше, чем веб-служба. Например, такие протоколы с большей вероятностью будут иметь дело с восстановлением после ошибок, частичной загрузкой и т. д.

Однако если вы собираетесь использовать для этой цели веб-службы в .NET, вам следует использовать WCF, если это вообще возможно. Помимо других преимуществ, WCF обрабатывает потоковую передачу и, следовательно, будет намного эффективнее с точки зрения использования памяти. Я обеспокоен тем, что если вы будете следовать двум (точным) предложениям выше, вашим следующим результатом будут исключения «недостаточно памяти или ресурсов», поскольку старая технология ASMX пытается загрузить весь ваш 25-мегабайтный файл в память сразу. На самом деле он может иметь в памяти несколько копий одновременно!

person John Saunders    schedule 15.06.2009

Если бы мне пришлось использовать веб-сервисы и поддерживать очень большие файлы, я бы посмотрел на внедрение системы, позволяющей загружать файлы по частям.

Eg.

  • ticketId GetTicket(размер)
  • UploadData(ticketId, byte[] payload) (можно вызывать сколько угодно раз)
  • FinalizeUpload (тикетид)

Это позволит вам разбивать большие загрузки и не хранить слишком много данных в памяти. Недостатком является то, что вы по-прежнему используете довольно неэффективный транспортный механизм.

person Sam Saffron    schedule 15.06.2009
comment
Это действительно должно быть приемлемым решением, поскольку оно требует меньше памяти и может даже поддерживать параллелизм. - person user420667; 06.10.2017

Просто чтобы добавить информацию для людей, гуглящих этот web.config:

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI

<location path="Copy.asmx"> <!-- Name of you asmx -->
    <system.webServer>
      <security>
        <requestFiltering>
          <requestLimits maxAllowedContentLength="104857600"/> <!-- 100 megs -->
        </requestFiltering>
      </security>
    </system.webServer>
  </location>

Это решило нашу проблему после устранения этой проблемы в течение довольно долгого времени.

person sonstabo    schedule 19.10.2010

Если вы настроены на использование веб-служб для перемещения файлов, я бы по крайней мере рассмотрел возможность использования вложений WS-Attachment/DIME. Основная проблема с отправкой byte[] через веб-службы заключается в том, что они помещаются в тело SOAP, которое кодируется как строка с основанием 64. Такое кодирование файлов увеличивает размер файла на целых две трети в теле мыла (т. е. файл размером 6 МБ становится файлом размером 9 МБ по сети).

Вполне вероятно, что ваша загрузка размером 25 МБ превращается в ОГРОМНЫЕ мыльные конверты.

Я настоятельно рекомендую прочитать это. Это может помочь вам попасть в DIME.

Вот отрывок.

Набор инструментов Microsoft WSE Toolkit позволяет отправлять большие вложения вместе с методом веб-службы с использованием стандартов DIME и WS-Attachments. Мы рассмотрим эти стандарты и объясним, почему они более эффективны, чем отправка больших объемов двоичных данных в вызове веб-службы с помощью других распространенных средств.

Надеюсь, это поможет!

person Tyler    schedule 15.06.2009
comment
Именно то, что я собирался предложить. XML-фильтры отказа в обслуживании будут буферизовать все сообщение SOAP, а размер буфера ограничен. Отправка двоичного файла в кодировке base-64 в качестве вложения позволяет избежать этого. DIME также упростит использование сервиса для Java, PHP и других клиентов. - person R Ubben; 16.06.2009
comment
Извините, но WSE УСТАРЕЛ. НЕ ИСПОЛЬЗУЙТЕ ЭТО, ЕСЛИ У ВАС НЕТ ВООБЩЕ НИКАКИХ ДРУГИХ ВЫБОРОВ. Извините, что кричу, но, похоже, не все это слышали или не все поняли намек на то, что WSE не поддерживается в Visual Studio 2008 или выше. - person John Saunders; 16.06.2009
comment
Джон делает отличное замечание, WSE IS устарел, и его дорожная карта довольно мрачна по сравнению с WCF. При этом, если мы говорим об обновлениях существующей веб-службы, которая не собирается быть переработанной для WCF (или инфраструктура .NET v3.0+ нежизнеспособна), я буду придерживаться своего оружия и рекомендую DIME /WS-приложение. - person Tyler; 16.06.2009
comment
@Tyler: вы можете проверить мой профиль здесь и посмотреть, прояснит ли это ситуацию. Правильное слово для WSE не устарело, оно устарело. Это намного ближе к фактическому неподдерживанию, чем можно было бы предположить из-за устаревшего. Действительно, правильный ответ для WSE — просто не ходить туда. См. social.msdn.microsoft. .com/Forums/en-US/asmxandxml/thread/. - person John Saunders; 16.06.2009
comment
Это спасло меня после 2 часов поиска, если ваш лимит файла составляет 10 мгб, вам нужно установить гораздо больший лимит на веб-сервис. Спасибо - person koolaang; 16.01.2019

maxRequestLength указывается в КБ, а не в байтах. Это должно дать вам ограничение в 30 МБ в течение 4-минутного тайм-аута.

<httpRuntime executionTimeout="240" maxRequestLength="30000" />

Наличие слишком высоких чисел может на самом деле препятствовать применению ваших значений. Думаю, я столкнулся с этим несколько лет назад, когда подумал, что это ограничение в байтах (нечеткая память).

person richardtallent    schedule 15.06.2009
comment
Я изменил на эти значения, тот же результат. Значения, которые у меня есть, были взяты из этой (несколько связанной/не связанной) статьи: support.microsoft.com/kb /925083 — оба набора значений имеют одинаковую проблему. - person ChrisHDog; 16.06.2009
comment
Какой у вас установлен ScriptTimeout на принимающей странице? - person richardtallent; 16.06.2009

Это конкретно не отвечает на ваш вопрос, но в прошлом я использовал WCF для передачи имен/путей/списков файлов, но затем использовал библиотеку FTP для передачи файла через FTP.

person NotDan    schedule 15.06.2009

это сработало для меня:

            <binding name="uploadFilesBasicHttpBinding" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" receiveTimeout="00:10:10" sendTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00">
                <readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxDepth="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647"/>
                <security mode="TransportWithMessageCredential">
                    <message clientCredentialType="UserName"/>
                </security>
            </binding>
person Dragos Durlut    schedule 14.11.2011
comment