в

Kazan Dev Alliance

Казанское Сообщество Разработчиков Программного Обеспечения

Персональный блог Александра Шера

Professional blog for .Net programmers. Main topics: Microsoft ASP.NET AJAX, WPF/E, OOP, Refactoring

June 2007 - Posts

  • Немного о HttpResponse.Flush

    Несколько раз за последнее время наталкивался в форумах на вопросы, связанные с использованием HttpResponse.Flush() В связи с этим решил сделать некоторое обощение этих вопросов и представить ответы, которые мне кажуться правильными 8). Критика и замечания приветствуются.

    - HttpResponse.Flush()не работает при вызове внутри обработчика события Page.Load/GridView.RowCreated/Button.Click

    Вызов HttpResponse.Flush() приводит к выводу всех данных из HttpResponse.OutputStream. При условии, что есть что выводить. Если ничего туда явно не занести, то при обычном течении жизненного цикла страницы HttpResponse.OutputStream начинает заполнятся только на Page.Render. Соответственно, вызов на более ранней стадии ничего не дает, т.к. в этот момент HttpResponse.OutputStream пуст.

    - Переопределять Render каждый раз, когда нужно вызвать HttpResponse.Flush(), не очень охота. Нельзя ли как-нибудь попроще?

    Один из вариантов - сделать контрол-пустышку и переопределить у него Render:

    [code language="C#"]

    public class FlushControl : Control {
         protected override void Render(HtmlTextWriter writer) {
             base.Render(writer);
             Page.Response.Flush();
        }
    }

    [/code]

    Если, например, добавить этот контрол в ItemTemplate репитера, то HttpResponse.Flush() будет вызываться при рендеринге каждого айтема.

    - В гриде 20 строк, но значение одной из ячеек вычисляется по полсекунды на каждую. Предыдущий вариант не катит.

    Панацеи, как известно, не существует. Один из вариантов - перенести вызов метода вычисления значения в Render. Перенести все это по-быстрому можно используя анонимные делегаты. Другой вариант - задейстовать AJAX и запонлять значения уже после загрузки страницы. Для этих целей неплохо подходит механизм PageMethods. Но в любом случае, постарайтесь не использовать вот это:

    - Хочу отрендерить контрол прямо внутри обработчика события Page.Load/GridView.RowCreated/Button.Click

    Сделать это не сложно:

    [code language="C#"]

    myControl.RenderControl(new HtmlTextWriter(Page.Response.Output));
    Page.Response.Flush();

    [/code]

    Но насколько это хорошо? Во-первых, данный контрол, отрендерившись, окажется в самом вначале всей страницы. Прощай разметка. Во-вторых, если не выставить ему Visible=false либо как-то иначе отключить рендеринг, контрол отрисуется ещё раз. В-третьих, всё, что будет происходить в жизненном цикле страницы, непонятно как будет влиять на контрол. Как поведет себя ViewState, сработают ли события, как отреагируют на преждевременный рендеринг другие контролы - все это остается неизвестным.

    Поэтому делать так можно только в том случае, если Вы ПОЛНОСТЬЮ взяли на себя управление рендерингом на данной странице.

    - Что это за свойства HttpResponse.Buffer и HttpResponse.BufferOutput ?

    Оба эти свойства (одно является оберткой другого) включают/выключают буфферизацию. Ставить им значение false надо очень осторожно, потому что, с одной стороны, страница начинает отображаться постепенно, но с другой, суммарное время отрисовки увеличивается, в некоторых случаях в десятки раз.

    - Как сочетаются HttpResponse.Flush() и UpdatePanel ?

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

  • То, что не вошло в презентацию

     Так уж получилось, что одна, на мой взгляд важная тема, не была затронута ни на одном из моих докладов по Microsoft ASP.NET AJAX. Поэтому вкратце расскажу о ней здесь.

    Дело в том, что асинхронный запрос, выполненный не вручную, а с помощью UpdatePanel triggers, имеет свой собственный цикл событий, именуемый Client Page Life-cycle. Выглядит он так:

    Все события Client Page Life-cycle - это события синглтона PageRequestManager. Каждое событие служит определенной цели.

    • initializeRequest может быть использован для отмены запроса (например в случае, если в данный момент некоторый запрос уже выполняется).
    • beginRequest вызывается непосредственно перед отправкой запроса на сервер, поэтому разумно использовать его для запуска прелодера.
    • Свойство PageLoadingEventArgs.panelsDeleting (событие pageLoading) содержит массив панелей, которые будут удалены в результате постбэка.
    • pageLoaded можно использовать для получения информации о панелях, которые были обновлены или созданы.
    • EndRequestEventArgs содержит информацию об ошибке (при условии что ошибка есть), а также ссылку на экземпляр объекта Sys.Net.WebRequestExecutor, использовавшегося при данном запросе.
© 2007 Kazan Developers Community and Post`s Authors