Как поймать ConfigurationErrorsException для нарушения maxRequestLength?

Я ограничиваю размер файла, который пользователи могут загружать на сайт из Web.config. Как описано здесь, он должен вызывать исключение ConfigurationErrorsException, если размер не принят. Я попытался поймать его из метода действия или контроллера для загрузки запросов, но не повезло. Соединение сбрасывается, и я не могу заставить его показать страницу с ошибкой.

Я попытался поймать его в событии BeginRequest, но независимо от того, что я делаю, исключение не обрабатывается. Здесь код:

protected void Application_BeginRequest(Object sender, EventArgs e)
{
    HttpContext context = ((HttpApplication)sender).Context;
    try
    {
        if (context.Request.ContentLength > maxRequestLength)
        {
            IServiceProvider provider = (IServiceProvider)context;
            HttpWorkerRequest workerRequest = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));

            // Check if body contains data
            if (workerRequest.HasEntityBody())
            {
                // get the total body length
                int requestLength = workerRequest.GetTotalEntityBodyLength();
                // Get the initial bytes loaded
                int initialBytes = 0;
                if (workerRequest.GetPreloadedEntityBody() != null)
                    initialBytes = workerRequest.GetPreloadedEntityBody().Length;
                if (!workerRequest.IsEntireEntityBodyIsPreloaded())
                {
                    byte[] buffer = new byte[512];
                    // Set the received bytes to initial bytes before start reading
                    int receivedBytes = initialBytes;
                    while (requestLength - receivedBytes >= initialBytes)
                    {
                        // Read another set of bytes
                        initialBytes = workerRequest.ReadEntityBody(buffer, buffer.Length);

                        // Update the received bytes
                        receivedBytes += initialBytes;
                    }
                    initialBytes = workerRequest.ReadEntityBody(buffer, requestLength - receivedBytes);
                }
            }
        }
    }
    catch(HttpException)
    {
        context.Response.Redirect(this.Request.Url.LocalPath + "?action=exception");
    }
}

Но я все еще получаю следующее:

Maximum request length exceeded.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.Web.HttpException: Maximum request length exceeded.

Source Error: 

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Update:

Какой метод вызывает исключение? Если я прочитаю запрос, он вызывает исключение. Если я его вообще не читаю, я получаю "101 Connection Reset" в браузере. Что можно сделать здесь?

Ответ 1

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

Вы можете использовать компоненты Flash или Javascript, чтобы сделать это правильно, потому что эта вещь не может потерпеть неудачу.

Ответ 2

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

protected void Application_Error() {
     var lastError = Server.GetLastError();
     if(lastError !=null && lastError is HttpException && lastError.Message.Contains("exceed")) {
      Response.Redirect("~/errors/RequestLengthExceeded");
      }
    }   

Фактически, если размер файла превышает пределы ошибки HttpException возникает.

Также существует ограничение IIS на контент, который нельзя использовать в приложении. IIS 7 бросает

Ошибка HTTP 404.13 - Не найдено настроен модуль фильтрации запросов отклонить запрос, который превышает запросить длину содержимого.

Вы можете сделать это в Google, есть много информации об этой ошибке iis.

Ответ 3

Я не на 100% на это, но я думаю, что это может помочь, если вы попытались изменить:

context.Response.Redirect(this.Request.Url.LocalPath + "?action=exception");

к

Server.Transfer(this.Request.Url.LocalPath + "?action=exception,false)

Мое мышление заключается в том, что запрос Over-max-request-length по-прежнему обрабатывается в вызове Redirect, но если вы сообщите ему, чтобы он удалил данные формы, он будет находиться под максимальной длиной запроса, а затем он может вести себя по-разному.

Нет гарантий, но его легко проверить.

Ответ 4

   catch (Exception ex)
   {
       if (ex is HttpException && (ex as HttpException).WebEventCode == 3004)
       {
            //-- you can now inform the client that file uploaded was too large.
       }
       else
           throw;
   }

Ответ 5

У меня есть аналогичная проблема в том, что я хочу уловить исключение "Максимальная длина запроса превышена" в обработчике Application_Error, а затем сделать перенаправление.

(Разница заключается в том, что я пишу службу REST с помощью ASP.Net Web API и вместо перенаправления на страницу с ошибкой я хотел перенаправить на контроллер ошибок, который затем вернет соответствующий ответ).

Однако я обнаружил, что при запуске приложения через сервер разработки ASP.Net Response.Redirect, похоже, не работает. Fiddler будет указывать на ошибку "ReadResponse(): сервер не ответил на этот запрос."

Мой клиент (Advanced REST Client для Chrome) просто покажет "0 NO RESPONSE".

Если я затем запустил приложение через локальную копию IIS на моей машине разработки, перенаправление будет работать правильно!

Я не уверен, что могу окончательно сказать, что Response.Redirect не работает на сервере разработки ASP.Net, но он, безусловно, не работал в моей ситуации.

Итак, я рекомендую попробовать запустить приложение через IIS вместо IIS Express или сервера разработки и посмотреть, есть ли у вас другой результат.

См. эту ссылку о том, как указать веб-сервер для веб-проектов в Visual Studio:

http://msdn.microsoft.com/en-us/library/ms178108(v=vs.100).aspx