2009-02-19 7 views
13

Tengo una página aspx donde estoy permitiendo que un usuario cargue un archivo y quiero limitar el tamaño máximo de carga del archivo a 10 MB. IIS7, .NET 3.5. Tengo el siguiente configurado en mi archivo web.config:¿Dónde puedo capturar y manejar maxAllowedContentLength excedido en 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> 

que tienen un error personalizado módulo que implementa el manejo de IHttpModule. Descubrí que cuando se excede el maxRequestLength, HttpApplication.Error se eleva. Sin embargo, cuando juego con maxAllowedContentLength, el evento HttpApplication.Error no se genera y el usuario se redirige a una página 404.13. Me he conectado con Visual Studio con excepciones de primera oportunidad activadas, no se lanza nada.

Mi primer pensamiento es verificar la longitud del contenido del encabezado en un evento anterior - ¿hay recomendaciones/mejores prácticas de dónde hago esto? PostLogRequest? EndRequest?

Respuesta

14

Después de mirar el ASP.NET Application Life Cycle Overview for IIS 7.0 y hacer mi propia experimentación, supongo que la validación de la solicitud se realiza internamente por IIS antes de que se produzca alguno de los eventos.

Parece que solo se generan LogRequest, PostLogRequest, EndRequest, PreSendRequestContent y PreSendRequestHeaders después de la validación interna con este error.

He decidido adjuntar un controlador de eventos al evento HttpApplication.EndRequest en mi controlador de errores personalizado y verificar el código de estado 404.13 en POST y manejarlo cuando necesito que se maneje, que en mi caso es redirigir al llamando a la página que marcará Server.GetLastError() y mostrará un error amistoso para el usuario final.

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); 
    } 
} 

Me gustaría recibir comentarios sobre este enfoque y las alternativas.

+0

Tenga en cuenta que la respuesta de sunflowerpower solo funciona si el modo de canal administrado está configurado como integrado. Al menos es por eso que experimenté – Marvin

+0

Me doy cuenta de que esta solución no maneja la Autenticación correctamente. Cuando llamo a Server.Transfer, las rutinas de verificación de autenticación de la página de destino fallan porque la propiedad HttpContext.Current.User es NULL. No parece ser causada por borrar los encabezados, ya que sacar esa línea aún resulta en el problema. ¿Hay alguna forma de evitar esto? No es una solución de lo contrario. – Triynko

+0

Pongo el código de error de @Triynko en su controlador de eventos. Estoy usando Umbraco: no estoy seguro de si eso es significativo, pero este es el único lugar donde he podido detectar las excepciones de "Máxima longitud de solicitud excedida". También tuve que llamar a 'Response.ClearContent();' para eliminar el YSOD. 'Application_Error' no se activa para esta excepción (aunque lo hace para RequestValidation) y no pude hacer que 'OnError' se active en un UserControl o Masterpage. No se pudo encontrar una página real. ;) –

3

El método más simple es manejarlo en el método OnError de la página.

Creo que esto solo funciona en .NET 4.0, ya que la propiedad WebEventCode está documentada como NUEVA en .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); 
    } 
} 

Lo que hice fue:

  • obtener el último error con Server.GetLastError
  • cheque que se trata de una "longitud máxima de la solicitud superado." error (WebEventCode == 3004).
  • añade un valor a las colecciones Context.Items a la bandera de la solicitud como un error
  • transferencia de la solicitud de vuelta a la página en sí con Server.Transfer (Context.Request.Url.LocalPath)
  • de la página método comprueba OnLoad para el indicador de error y muestra un mensaje si está presente

Esto garantiza que el error se maneje por completo en la página solicitada, y la página puede informar de errores.

También tenga en cuenta que si bien el navegador finalmente recibirá una respuesta adecuada, el navegador puede tomar su tiempo para cargar la solicitud completa antes de que maneje la respuesta del servidor y la muestre. Este comportamiento probablemente se define como parte de la interacción servidor/navegador en el protocolo HTTP, por lo que probablemente no se puede hacer mucho al respecto.

+0

A veces devuelve el código '0'. –

+0

Lo usé para el control ... http://stackoverflow.com/a/665591/221683 –

Cuestiones relacionadas