2009-06-15 21 views
28

Ho un servizio Web che accetta un byte [] e lo salva.Come caricare file di grandi dimensioni (> 25 MB) in un servizio Web?

Questo funziona bene per i file "piccoli", ma una volta che si raggiunge una determinata dimensione il servizio Web non riesce e restituisce "La richiesta non è riuscita con stato HTTP 404: non trovato".

Da quello che ho visto sembra essere un'impostazione IIS che limita le dimensioni di un file che può essere pubblicato (per prevenire attacchi di tipo Denial of Service). Ho provato ad aumentare questa impostazione, ma ho difficoltà a determinare quale impostazione e dove/come si vorrebbe impostare. Sto usando IIS7 e il webservice è fatto in .net (asmx).

Nel web.config del servizio web ho aggiunto quanto segue (che sembrava aumentare la dimensione del file che può essere accettato, ma non fino in fondo a questa dimensione impostazione)

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

Qualsiasi suggerimenti su dove (e come) aumentare la dimensione del file che il servizio web sarebbe molto apprezzato.

+0

Per quanto riguarda WCF/FTP/WS-Allegato/DIME: suggerimenti eccellenti e alcune interessanti letture. Questi sono probabilmente i tipi di soluzioni a lungo termine che finirò per usare. Tuttavia se ci fosse qualche soluzione a breve termine per cambiare la dimensione del caricamento in IIS7 sarebbe eccellente. Grazie. – ChrisHDog

risposta

31

In aggiunta a httpRuntime/maxRequestLength menzionato nella domanda, sembra che vi sia un elemento aggiuntivo che può essere aggiunto al file web.config del servizio Web per consentire trasferimenti di file di grandi dimensioni.

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

Questo sembra consentire il caricamento di file di grandi dimensioni tramite servizi Web.

+5

Solo una nota su questo: un'indicazione che manchi questa impostazione è quando si ottiene un 404 dal servizio WCF ma non c'è alcun messaggio di errore nella traccia WCF (sì, molto utile lo so - grazie WCF). Sono contento che tu abbia trovato questo Chris, mi hai salvato sprecando altre ore su questo. –

+0

Sì, questa impostazione "extra" ha sprecato molte ore della mia giornata oggi. Non mi ero reso conto che, con IIS7, hai bisogno di citare il file più grande in DUE posti nel tuo web.config. Ma, sì, con questa impostazione maxAllowedContentLength in atto, ho potuto finalmente caricare file 31Mb. –

+2

@AndyBritcliffe "Grazie WCF". In questo caso, mi sembra che il 404 provenga da IIS stesso, quindi WCF probabilmente non ha nemmeno sentito parlare dell'evento, e quindi ha avuto poche possibilità di registrare qualcosa a riguardo. Riformulare su "Grazie Microsoft", e la critica continua a essere valida. :) –

1

maxRequestLength è in KB, non in byte. Questo dovrebbe darti un limite di 30 MB entro una finestra di timeout di 4 minuti.

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

Avere numeri troppo alti potrebbe effettivamente impedire l'applicazione dei valori. I penso Mi sono imbattuto in questo alcuni anni fa quando pensavo che fosse un limite di byte (memoria vaga).

+0

Sono passato a questi valori, lo stesso risultato. I valori che ho sono stati presi da questo articolo (in qualche modo correlato/in qualche modo non correlato): http://support.microsoft.com/kb/925083 - entrambi i set di valori sembrano avere lo stesso problema. – ChrisHDog

+0

A che cosa è impostato ScriptTimeout sulla pagina di ricezione? – richardtallent

5

È necessario tenere presente che i servizi Web non sono progettati principalmente come meccanismi di trasferimento file. Qualsiasi protocollo di trasferimento file progettato appositamente farà probabilmente un lavoro migliore di un servizio web. Ad esempio, tali protocolli hanno maggiori probabilità di gestire il recupero degli errori, caricamenti parziali, ecc.

Tuttavia, se si intende utilizzare i servizi Web per questo scopo in .NET, è necessario utilizzare WCF, se possibile. . Tra gli altri vantaggi, WCF gestisce lo streaming e sarà quindi molto più efficiente in termini di utilizzo della memoria. Sono preoccupato che se segui i due (accurati) suggerimenti sopra, il tuo prossimo risultato saranno eccezioni "esaurite di memoria o risorse", dato che la vecchia tecnologia ASMX prova a caricare l'intero file da 25MB in memoria in una volta. In effetti, potrebbe avere più copie in memoria allo stesso tempo!

1

Questo non risponde in modo specifico alla domanda, ma quello che ho fatto in passato è usare WCF per trasferire nomi di file/percorsi/elenchi, ma poi usare una libreria FTP per trasferire il file tramite FTP.

3

Se si è deciso di utilizzare i servizi Web per spostarsi tra i file, prenderei in considerazione almeno l'utilizzo degli allegati WS-Attachment/DIME. Il problema principale con l'invio di servizi web su byte [] è che vengono inseriti nel corpo SOAP che viene codificato come una stringa 64 di base. I file di codifica come questo aumentano le dimensioni del file fino a due terzi nel corpo del sapone (ad esempio un file da 6 MB diventa un file da 9 MB sul filo).

È probabile che il caricamento da 25 MB si trasformi in buste di sapone enormi.

Suggerisco caldamente reading this. Quale potrebbe farti entrare in DIME.

Ecco un estratto.

WSE Toolkit di Microsoft permette grandi allegati da inviare insieme a un metodo di servizio Web utilizzando il DIME e WS-Allegati standard. Sarà esaminare questi standard e il motivo per cui sono più efficienti dell'invio di grandi quantità di dati binari in una chiamata di servizio Web tramite altri mezzi comuni .

Spero che questo aiuti!

+2

Esattamente quello che stavo per suggerire. I filtri XML Denial of Service bufferano l'intero messaggio SOAP e la dimensione del buffer è limitata. L'invio del binario codificato in base 64 come allegato lo evita. DIME renderà più semplice l'uso del servizio anche per Java, PHP e altri client. –

+4

Siamo spiacenti, ma WSE È OBSOLETO. NON UTILIZZARLO A MENO CHE NON SIA NESSUN ALTRO SCELTA. Mi dispiace di urlare, ma sembra che non tutti abbiano sentito questo, o non tutti hanno preso il suggerimento che WSE non è supportato in Visual Studio 2008 o versioni successive. –

+0

John è un ottimo punto, WSE IS è deprecato e la sua road map è piuttosto tetra rispetto a WCF. Detto questo se stiamo parlando di aggiornamenti a un servizio web esistente che non sta per essere revisionato su WCF (o il framework .NET v3.0 + non è fattibile) mi attaccherò alle mie pistole e raccomanderò DIME/WS-allegato. – Tyler

5

Se mi è stato impedito di utilizzare i servizi Web e avevo bisogno di supportare file molto grandi, vedrei l'implementazione di un sistema che consente di caricare file in pezzi.

Es.

  • TICKETID getticket (dimensione)
  • UploadData (TICKETID, byte [] payload) (questo può essere chiamato tutte le volte che si desidera)
  • FinalizeUpload (TICKETID)

Questo sarebbe consente di ridurre i grandi caricamenti e di non conservare troppi dati in memoria. Lo svantaggio è che si sta ancora utilizzando un meccanismo di trasporto abbastanza inefficiente.

+0

Questa dovrebbe essere la soluzione accettata perché richiede meno memoria e può persino supportare il parallelismo. – user420667

5

Giusto per aggiungere informazioni alle persone googling questo web.config:

C: \ Programmi \ File comuni \ 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> 

Ciò ha risolto il nostro problema dopo aver risolto questo problema per un bel po 'di tempo.

0

questo ha funzionato per me:

  <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> 
Problemi correlati