2009-02-19 5 views
13

У меня есть страница aspx, где я разрешаю пользователю загружать файл, и я хочу ограничить максимальный размер загружаемого файла размером 10 МБ. IIS7, .NET 3.5. У меня есть следующий сконфигурирован в моем файле web.config:Где я могу поймать и обработать maxAllowedContentLength, превышенную в 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> 

У меня есть пользовательский модуль, который реализует IHttpModule обработки ошибок. Я обнаружил, что когда maxRequestLength превышено, HttpApplication.Error действительно поднят. Однако, когда я играю с maxAllowedContentLength, событие HttpApplication.Error не поднимается, и пользователь перенаправляется на страницу 404.13. Я подключился к Visual Studio с первым шансом, что ничто не забрасывается.

Моя первая мысль - проверить длину содержимого заголовка в более раннем событии - есть ли рекомендации/лучшие практики, где я это делаю? PostLogRequest? EndRequest?

ответ

14

Посмотрев на ASP.NET Application Life Cycle Overview for IIS 7.0 и сделав собственное экспериментирование, я предполагаю, что проверка запроса выполняется внутри IIS до того, как какое-либо из событий будет поднято.

Похоже, что после внутренней проверки с этой ошибкой возникают только логические запросы, PostLogRequest, EndRequest, PreSendRequestContent и PreSendRequestHeaders.

Я решил подключить обработчик событий к событию HttpApplication.EndRequest в своем обработчике ошибок и проверить код статуса 404.13 на POST и обработать, поскольку мне нужно, чтобы он обрабатывался, что в моем случае является перенаправлением на вызывающую страницу, которая проверит Server.GetLastError() и покажет дружественную ошибку конечному пользователю.

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

Я бы приветствовал отзыв об этом подходе и альтернативах.

+0

Пожалуйста, не отвечайте на ответ подсолнечной энергии, только если для управляемого режима трубопровода установлено значение Интегрировано. По крайней мере, вот почему я испытал – Marvin

+0

. Я замечаю, что это решение не обрабатывает аутентификацию должным образом. Когда я вызываю Server.Transfer, процедуры проверки подлинности целевой страницы терпят неудачу, потому что свойство HttpContext.Current.User равно NULL. Похоже, что это не вызвано очисткой заголовков, так как принятие этой строки все еще приводит к этой проблеме. Есть ли способ обойти это? В противном случае это не решение. – Triynko

+0

Я установил код ошибки @Triynko в обработчик события. Я использую Umbraco - я не уверен, что это важно, но это единственное место, которое я смог уловить «Превышение максимальной длины запроса». Мне также пришлось вызвать «Response.ClearContent();» для удаления YSOD. «Application_Error» не срабатывает для этого исключения (хотя это делает для RequestValidation), и я не мог получить «OnError» для запуска в UserControl или Masterpage. Не удалось найти фактическую страницу. ;) –

3

Самый простой способ - обработать его в методе OnError самой страницы.

Я думаю, что это работает только в .NET 4.0, поскольку свойство WebEventCode зарегистрировано как NEW в .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); 
    } 
} 

Что я сделал:

  • получить последнюю ошибку с Server.GetLastError
  • проверить, что это "Максимальная длина запроса превышено." ошибка (WebEventCode == 3004).
  • добавили значение Context.Items коллекций пометить запрос как ошибку
  • передачи запроса обратно на саму страницу с Server.Transfer (Context.Request.Url.LocalPath)
  • данной страницы метод OnLoad проверяет для флага ошибки и отображает сообщение, если оно присутствует

Это гарантирует, что ошибка полностью обрабатывается на запрошенной странице, и страница способна сообщать об ошибках.

Также обратите внимание, что, хотя браузер в конечном итоге получит надлежащий ответ, браузер может занять свое время, загружая весь запрос, прежде чем обрабатывать ответ сервера и отображает его. Такое поведение, вероятно, определяется как часть взаимодействия между сервером и браузером в протоколе HTTP, поэтому, вероятно, об этом мало что можно сделать.

+0

Иногда он возвращает код '0'. –

+0

Я использовал это для проверки ... http://stackoverflow.com/a/665591/221683 –

 Смежные вопросы

  • Нет связанных вопросов^_^