Комментарии 9
Гугл подсказал, что всё же проще так перехватывать исключение:
public override void Init()
{
base.Init();
Error += ErrorHandler;
}
private void ErrorHandler(object sender, EventArgs args)
{
var ex = Server.GetLastError().InnerException as HttpException;
if(ex != null && ex.WebEventCode == System.Web.Management.WebEventCodes.RuntimeErrorPostTooLarge)
{
// Maximum request length exceeded.
}
}
Прошу прощения, Хабр по кнопке code вставляет тег code, а надо оказывается source. Исправляюсь:
public override void Init()
{
base.Init();
Error += ErrorHandler;
}
private void ErrorHandler(object sender, EventArgs args)
{
var ex = Server.GetLastError().InnerException as HttpException;
if(ex != null && ex.WebEventCode == System.Web.Management.WebEventCodes.RuntimeErrorPostTooLarge)
{
// Maximum request length exceeded.
}
}
Есть одна проблема с данным подходом: исключение будет брошено после полной загрузки. Если файл большой, не красиво выйдет, клиенту придется дождаться пока все отправится.
Для решения можно сделать HttpModule, в котором смотреть на httpWebRequest и его KnownHeaders для определения длина запроса. Так например neatUpload делает
Можно и процесс загрузки получать…
На клиенте же используется стандартный html fileupload контрол, в iframe
Отменять можно например как здесь — www.obout.com/fup/example_11.aspx
Для решения можно сделать HttpModule, в котором смотреть на httpWebRequest и его KnownHeaders для определения длина запроса. Так например neatUpload делает
Можно и процесс загрузки получать…
На клиенте же используется стандартный html fileupload контрол, в iframe
Отменять можно например как здесь — www.obout.com/fup/example_11.aspx
В описанном в статье подходе как раз-таки обработка происходит до выброса исключения. Т.е. ошибка предупреждается. Не очень понял, что подразумевалось под «полной загрузкой», но если Вы про создание объекта Request (типа HttpRequest) со всеми файлами, то HttpModule здесь не спасёт. Контекст запроса (вместе с Response и Request) создаётся до обработки события BeginRequest в HttpApplication и, соответственно, до вызова всех модулей.
Про Обаут знаю, но не наш вариант из-за платности контрола :( Всё равно спасибо за наводку.
Про Обаут знаю, но не наш вариант из-за платности контрола :( Всё равно спасибо за наводку.
А какая разница какой контрол? Данные то все равно уже на сервере «в полном объеме». Кастомный HttpException кажется наилучшим решением (на любом удобном уровне до отправки ответа клиенту).
К слову о том, как редиректить по конкретной ошибке — можно заюзать subStatusCode (IIS 7+).
К слову о том, как редиректить по конкретной ошибке — можно заюзать subStatusCode (IIS 7+).
> А какая разница какой контрол? Данные то все равно уже на сервере «в полном объеме».
Разница есть. Если использовать html5, flash или silverlight можно сделать загрузку чанками, причем запрашивать на сервере максимальный размер чанка. Со стандартным контролом input type=«file» так не выйдет.
Данные на сервере в полном объеме только по тому, что вы вызываете Requset, что заставляет его ресолвиться полностью.
Есть способ доступа к размеру загружаемого контента в начале загрузки. При этом клиенту можно сообщить, что размер превышен, и таким образом он сможет прервать загрузку.
Вот код из моего модуля загрузки:
Дальше делаем httpHandler с отдачей процента загрузки
Статус ставится объекту класса UploadStatus. Он у нас [DataContract].
Вобщем принцип думаю понятен.
Главное что такой подход позволяет делать запросы на сервер в процессе загрузки. Если пытаться опрашивать сервак, используя Request, ничего не выйдет, ответ получите после полной загрузки вашего файла.
Ну и отменить загрузку конечно можно.
Разница есть. Если использовать html5, flash или silverlight можно сделать загрузку чанками, причем запрашивать на сервере максимальный размер чанка. Со стандартным контролом input type=«file» так не выйдет.
Данные на сервере в полном объеме только по тому, что вы вызываете Requset, что заставляет его ресолвиться полностью.
Есть способ доступа к размеру загружаемого контента в начале загрузки. При этом клиенту можно сообщить, что размер превышен, и таким образом он сможет прервать загрузку.
Вот код из моего модуля загрузки:
private const string C_MARKER = "multipart/form-data; boundary=";
private HttpWorkerRequest GetWorkerRequest(HttpContext context)
{
IServiceProvider provider = context;
// если траблы с доступом - используем
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
return (HttpWorkerRequest) provider.GetService(typeof (HttpWorkerRequest));
}
private void Context_AuthenticateRequest(object sender, EventArgs e)
{
var app = sender as HttpApplication;
HttpWorkerRequest worker = GetWorkerRequest(app.Context);
int bufferSize;
string boundary;
string ct;
bool statusPersisted = false;
// заголовок запроса (multipart form data)
ct = worker.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentType);
// application/x-www-form-urlencoded
// проверка что это именно форма с файлом. еще и параметр запроса проверяем
if (worker.GetQueryString() == "upload" && ct != null &&
string.Compare(ct, 0, C_MARKER, 0, C_MARKER.Length, true, CultureInfo.InvariantCulture) == 0)
{
long length = long.Parse(worker.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));
if (length > 0)
{
if (length/1024 > GetMaxRequestLength(app.Context))
{
// здесь ставим статус "Запрос превышен". Клиент сможет его забрать и отменить загрузку
}
.....
Дальше делаем httpHandler с отдачей процента загрузки
/// <summary>
/// отдаем процент загрузки
/// </summary>
public void GetProgress()
{
UploadStatus status = UploadManager.Instance.Status;
m_message = new CMessageXml(status ?? UploadStatus.EMPTY_STATUS);
// дальше в классе делаем Response.Write(m_message.ToString());
// Response.End();
}
Статус ставится объекту класса UploadStatus. Он у нас [DataContract].
Вобщем принцип думаю понятен.
Главное что такой подход позволяет делать запросы на сервер в процессе загрузки. Если пытаться опрашивать сервак, используя Request, ничего не выйдет, ответ получите после полной загрузки вашего файла.
Ну и отменить загрузку конечно можно.
> Данные на сервере в полном объеме только по тому, что вы вызываете Requset, что заставляет его ресолвиться полностью.
А не могли бы ссылку дать, откуда такая информация?
А не могли бы ссылку дать, откуда такая информация?
посмотрел как геттер сделан:
Так что данные на сервере не из-за обращения к Request.ContentLength, это да.
Просто загрузку никто не прерывает, вот в чем дело. Даже если сделать сабмит формы с файлом в iframe, мы же должны получить ответ, что размер превышен, причем получим его в тот же iframe.
Чтобы можно было прервать, нельзя к Request обращаться в модуле загрузки, про который писал. У меня все заработало, только когда убрал обращение во всех классах. Иначе запросы статуса ждали окончания загрузки, потом выдавали 100%.
public int ContentLength
{
get
{
if ((this._contentLength == -1) && (this._wr != null))
{
string knownRequestHeader = this._wr.GetKnownRequestHeader(11);
if (knownRequestHeader != null)
{
try
{
this._contentLength = int.Parse(knownRequestHeader, CultureInfo.InvariantCulture);
}
catch
{
}
}
else if (this._wr.IsEntireEntityBodyIsPreloaded())
{
byte[] preloadedEntityBody = this._wr.GetPreloadedEntityBody();
if (preloadedEntityBody != null)
{
this._contentLength = preloadedEntityBody.Length;
}
}
}
if (this._contentLength < 0)
{
return 0;
}
return this._contentLength;
}
}
Так что данные на сервере не из-за обращения к Request.ContentLength, это да.
Просто загрузку никто не прерывает, вот в чем дело. Даже если сделать сабмит формы с файлом в iframe, мы же должны получить ответ, что размер превышен, причем получим его в тот же iframe.
Чтобы можно было прервать, нельзя к Request обращаться в модуле загрузки, про который писал. У меня все заработало, только когда убрал обращение во всех классах. Иначе запросы статуса ждали окончания загрузки, потом выдавали 100%.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Обработка исключений «Maximum request length exceeded» в ASP.NET