2009-02-19 11 views
13

Ho una pagina aspx in cui sto consentendo a un utente di caricare un file e voglio limitare la dimensione massima del caricamento del file a 10 MB. IIS7, .NET 3.5. Ho il seguente configurato nel mio file web.config:Dove posso rilevare e gestire maxAllowedContentLength superato in IIS7?

<location path="foo.aspx"> 
    <system.web> 
     <!-- maxRequestLength: kbytes, executionTimeout:seconds --> 
     <httpRuntime maxRequestLength="10240" executionTimeout="120" /> 
     <authorization> 
      <allow roles="customRole"/> 
      <!-- Deny everyone else --> 
      <deny users="*"/> 
     </authorization> 
    </system.web> 
    <system.webServer> 
     <security> 
      <requestFiltering> 
       <!-- maxAllowedContentLength: bytes --> 
       <requestLimits maxAllowedContentLength="10240000"/> 
      </requestFiltering> 
     </security> 
     <handlers accessPolicy="Read, Script"> 
      <add name="foo" path="foo.aspx" verb="POST" 
       type="System.Web.UI.PageHandlerFactory" 
       preCondition="integratedMode" /> 
     </handlers>  
    </system.webServer> 
</location> 

Ho un errore personalizzato modulo che implementa IHttpModule manipolazione. Ho scoperto che quando viene superato maxRequestLength, viene effettivamente generato lo HttpApplication.Error. Tuttavia, quando gioco con maxAllowedContentLength, l'evento HttpApplication.Error non viene generato e l'utente viene reindirizzato a una pagina 404.13. Ho allegato con Visual Studio con le eccezioni di prima volta attivate, non viene generato nulla.

Il mio primo pensiero è di controllare la lunghezza del contenuto dell'intestazione in un evento precedente - ci sono raccomandazioni/buone pratiche su dove lo faccio? PostLogRequest? EndRequest?

risposta

14

Dopo aver esaminato lo ASP.NET Application Life Cycle Overview for IIS 7.0 e fatto la mia sperimentazione, suppongo che la convalida della richiesta venga eseguita internamente da IIS prima che uno qualsiasi degli eventi venga generato.

Sembra che solo LogRequest, PostLogRequest, EndRequest, PreSendRequestContent e PreSendRequestHeaders vengano generati dopo la convalida interna con questo errore.

Ho deciso di collegare un gestore di eventi all'evento HttpApplication.EndRequest nel mio gestore di errori personalizzato e controllare il codice di stato 404.13 su POST e gestire come ho bisogno di essere gestito, che nel mio caso è quello di reindirizzare al pagina chiamante che controllerà Server.GetLastError() e visualizzerà un errore amichevole all'utente finale.

private void application_EndRequest(object sender, EventArgs e) 
{ 
    HttpRequest request = HttpContext.Current.Request; 
    HttpResponse response = HttpContext.Current.Response; 

    if ((request.HttpMethod == "POST") && 
     (response.StatusCode == 404 && response.SubStatusCode == 13)) 
    { 
     // Clear the response header but do not clear errors and 
     // transfer back to requesting page to handle error 
     response.ClearHeaders(); 
     HttpContext.Current.Server.Transfer(
      request.AppRelativeCurrentExecutionFilePath); 
    } 
} 

Sarei felice di ricevere feedback su questo approccio e sulle alternative.

+0

La risposta di sunflowerpower funziona solo se la modalità pipeline gestita è impostata su integrata. Almeno questo è il motivo per cui ho sperimentato – Marvin

+0

Sto notando che questa soluzione non gestisce correttamente l'autenticazione. Quando chiamo Server.Transfer, le routine di verifica dell'autenticazione della pagina di destinazione non riescono perché la proprietà HttpContext.Current.User è NULL. Non sembra essere causato dalla cancellazione delle intestazioni, in quanto l'eliminazione di tale linea comporta ancora il problema. C'è un modo per aggirare questo? Altrimenti non è una soluzione. – Triynko

+0

Inserisco il codice di errore di @Triynko nel gestore di eventi. Sto usando Umbraco: non sono sicuro se ciò sia significativo, ma questo è l'unico posto in cui sono stato in grado di intercettare le eccezioni di "Lunghezza massima richiesta superata". Dovevo anche chiamare "Response.ClearContent();" rimuovere il YSOD. 'Application_Error' non si attiva per questa eccezione (anche se lo fa per RequestValidation) e non ho potuto ottenere 'OnError' per attivare un UserControl o una Masterpage. Impossibile trovare una pagina effettiva. ;) –

3

Il metodo più semplice è gestirlo nel metodo OnError della pagina stessa.

Penso che funzioni solo in .NET 4.0, poiché la proprietà WebEventCode è documentata come NUOVO in .NET 4.0.

protected override void OnError(EventArgs e) 
{ 
    Exception err = Server.GetLastError(); 
    if (err is HttpException) 
    { 
     if ((err as HttpException).WebEventCode == 3004) 
     { 
      Context.Items["error"] = "File exceeded maximum allowed length."; 
      Server.Transfer(Context.Request.Url.LocalPath); 
      return; 
     } 
    } 
    base.OnError(e); 
} 

protected override void OnLoad(EventArgs e) 
{ 
    base.OnLoad(e); 
    if (!IsPostBack) 
    { 
     string error = Context.Items["error"] as string; 
     if (!string.IsNullOrEmpty(error)) 
      showErrorMessage(error); 
    } 
} 

Quello che ho fatto è stato:

  • ottenere l'ultimo errore con Server.GetLastError
  • di controllo che si tratta di una "Lunghezza massima richiesta superato." errore (WebEventCode == 3004).
  • aggiunto un valore alle collezioni Context.Items per contrassegnare la richiesta come un errore
  • trasferimento della richiesta torna alla pagina stessa con Server.Transfer (Context.Request.Url.LocalPath)
  • della pagina controlli metodo OnLoad per il flag di errore e visualizza un messaggio se presente

Ciò garantisce che l'errore venga gestito interamente nella pagina richiesta e che la pagina sia in grado di segnalare errori.

Si noti inoltre che mentre il browser riceverà una risposta adeguata, il browser potrebbe impiegare del tempo a caricare l'intera richiesta prima di gestire la risposta del server e visualizzarla. Questo comportamento è probabilmente definito come parte dell'interazione server/browser nel protocollo HTTP, quindi probabilmente non si può fare molto a riguardo.

+0

A volte restituisce il codice '0'. –

+0

L'ho usato per il controllo ... http://stackoverflow.com/a/665591/221683 –