Подлипенский Павел

Блог о технологиях и деньгах

Скаженi кабани: GridView vs Response.Write

clock декабря 29, 2008 09:04 by author Подлипенский Павел

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

Что-то случилось...

... понял я, когда в час ночи зазвонил мой телефон. Сквозь сон я выслушал все новогодние "пожелания" заказчика и краткое описание проблемы - "Страница медленно работает". Затем пока нашел штаны, пока нашел где у меня ноги, пока оделся и, спустя часы, я оказался на работе. Нагрузочное (или даже стресc-тестирование) показало, что страница действительно забирает 90% процессорного времени при больших объемах данных на ней. После небольшого разбирательства выяснилось, что показания %Time in GC счетчика производительности меньше оптимальных. После чего наш консилиум заключил, что приложение нерационально использует оперативную память сервера.

MSDN говорит:

.NET CLR Memory\% Time in GC

Threshold: This counter should average about 5 percent for most applications when the CPU is 70 percent busy, with occasional peaks. As the CPU load increases, so does the percentage of time spent performing garbage collection. Keep this in mind when you measure the CPU.

Significance: This counter indicates the percentage of elapsed time spent performing a garbage collection since the last garbage collection cycle. The most common cause of a high value is making too many allocations, which may be the case if you are allocating on a per-request basis for ASP.NET applications. You need to study the allocation profile for your application if this counter shows a higher value.

За этим последовал небольшой code review, во время которого выяснилось, что приложение создает дофига коллекций. Коллекции использовались для переноса данных из BLL в Presentation Layer, и последующей конвертации их в DataTable (для байндига в GridView). Таким образом мы создали три анти-паттерна производительности (во завернул-то!): храним много данных в памяти, создаем большое количество циклов и конвертаций типов.

Пути решения

  • Байндить коллекции сразу GridView, без конвертации в DataTable
  • Создавать DataTable сразу из XML файла, минуя коллекции во избежания больших циклов  и конвертации типов
  • Использовать XSLT для трансофрмации XML в HTML таблицу (нафиг тогда вообще ASP.NET?)
  • Использовать Response.Write(), как это предлагает сделать Майкрософт

Решили попробовать последнее.

В результате получили следующее:

GridView Response.Write()
image_2 image_8

Интересные результаты, неправда ли? И хотя мы выиграли в производительности мы проиграли как минимум в удобстве и безопасности: GridView не просто рендерит таблицу, а и реализует некий функционал для управления и взаимодействия с данными в ней. А также делает проверки на cross-site scripting и другие виды атак. Так, что настаивать на Response.Write не буду. Решение использовать зависит от конкретной ситуации и пожеланий вашего заказчика.

Полезные ссылки

Improving ASP.NET Performance

Measuring .NET Application Performance

Code Review: .NET Application Performance

Текущий рейтинг: 5.0 (1 голосов)

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Динамическое добавление ASP.NET пользовательского контрола с использованием JQuery

clock сентября 9, 2008 09:58 by author Подлипенский Павел

Недавно у меня возникла необходимость динамически подгружать пользовательские контролы на страницу. Это довольно просто реализовывается с помощью UpdatePanel. Но мне этот вариант не подошел, так как страница должна весить как можно меньше и работать как можно быстрее. Поэтому выбор пал именно на связку ASP.NET и JQuery + Web Service. Для начала давайте разберемся каким образом можно вызвать Web Method с помощью JQuery.

function getJsonAjaxObject(webServiceURL, jsonData) {
 $.ajax({
  type: "POST",
  contentType: "application/json; charset=utf-8",
  url: serviceURL,
  data: jsonData,
  success:
   function(msg){
   //код обработки успешного вызова веб-метода
   },
  error:
   function(XMLHttpRequest, textStatus, errorThrown){
    //код обработки ошибки выполнения веб-метода
   }
 });
}

Из всего множества методов (load, get, post, getJSON, ajax) я выбрал именно ajax т.к. этот метод позволяет наиболее полно контролировать процесс создания асинхронного запроса к веб-сервису.

Имя Тип Описание параметра
type string возможные варианты – GET или POST. Если параметр упущен, то по умолчанию будет использоваться метод GET. Типы запроса PUT или DELETE тоже могут быть использованы, но они поддерживаются не всеми браузерами.
contentType string при передаче данных серверу сообщает content-type. По умолчанию - application/x-www-form-urlencoded.
url string адрес веб-сервиса. Например, http://mysite.com/myservice.asmx/mywebmethod
data object данные, передаваемые на сервер. Добавляются в URL GET-запроса. Если используется объект, он должен представлять собой пары ключ/значение. Если значения представлены в виде массива, jQuery сериализует значения с некоторым ключом. Например: {foo:["bar1", "bar2"]} будет представлено как "&foo=bar1&foo=bar2".
success function указывается функция, которая будет вызвана в случае успешного завершения запроса. Функция принимает два аргумента: данные, возвращенные с сервера и отформатированные с учетом параметра dataType и строка, описывающая статус ответа(в нашем примере это строка всегда будет “success”).
error function определяет функцию, которая будет вызвана в случае неуспешного выполнения запроса.
dataType string строка, описывает тип данных, которые ожидаются в качестве ответа сервера. Если не определена, то jQuery сам попытается определить тип, основываясь на MIME-типе ответа сервера. Доступные типы: - xml: вернет XML документ, который может быть обработан через jQuery. - html: вернет HTML как plain text. - script: расценивает ответ как JavaScript и возвращает его как plain text. - json: расценивает ответ как данные в формате JSON и возвращает JavaScript объект. - jsonp: загружает данные в формате JSON используя JSONP. Необходимо дополнительно добавить "?callback=?" в конец строки запроса в URL, чтобы определить вызов. (Добавлено в jQuery 1.2). - text: строка plain text.
async boolean
по умолчанию все запросы выполняются в асинхронном режиме (значение true). Если необходимо выполнить синхронный запрос, следует установить значение false для этой опции. Помните, что синхронный запрос может временно заблокировать браузер, запретив любые действия во время выполнения запроса.
beforeSend function
может содержать функцию, которая должна быть вызвана до передачи запроса. beforeSend - это Ajax Event (события рассмотрены в другой статье).
cache boolean
опция добавлена в jQuery 1.2. По умолчанию - true. Если установить в false, запрашиваемая страница не будет кэшироваться браузером.
complete function
определяет функцию, которая будет вызвана по окончанию запроса (успешного и ошибочного выполнения). Принимает два аргумента: объект XMLHttpRequest и строку, описывающую "успешность" запроса. complete - это Ajax Event (события рассмотрены в другой статье).
global boolean
true или false. Вызывать или нет глобальные обработчики событий Ajax для этого запроса. Может быть использована для контроля различных Ajax событий. По умолчанию - true.
ifModified boolean
запрос будет успешным только в случае, если данные ответа изменились со времени последнего запроса. По умолчанию - false.
processData boolean
по умолчанию true. В опции data данные представлены в виде объекта, который преобразуется в строку запроса, подходящую для content-type по умолчанию - "application/x-www-form-urlencoded". Если необходимо иное, установите опцию processData в false.
timeout number
устанавливает локальный тайм-аут для запроса в миллисекундах. Отменяет глобальный тайм-аут для этого запроса, если тот определен через $.ajaxSetup


Необходимо также учесть, что ASP.NET Ajax enabled веб-сервис разрешает только HTTP POST (по умолчанию) для вызова метода, который возвращает JSON.

В большинстве случаев IIS 6 и выше требует наличия content-length элемента в запросе POST, даже если данных в запросе нет. Content-length для запроса без данных должен быть равен 0, но JQuery, в таком случае, этот элемент не добавляет. Поэтому для readonly запросов POST необходимо указывать пустой JSON объект:

data: “{}”

Это натолкнет JQuery на мысль указать корректный content-length и ваш веб-сервис сможет правильно распознать readonly-запрос, отбросив при этом пустой параметр.

Хочу еще обратить ваше внимание на то, что contentType установлен в "application/json;charset=utf-8". Этого требует ASP.NET AJAX. JSON-запросы, не имеющие подобного заголовка будут проигнорированы ASP.NET.

Еще одна проблема, с которой мне пришлось столкнуться, это “Maximum length exceed” ошибка. Она возникает в случае, когда длина JSON-ответа превышает длину по умолчанию. Во избежание этой ошибки необходимо добавить в web.config следующее:

<system.web.extensions>
  <scripting>
     <webServices>
    <jsonSerialization maxJsonLength="5000000" />
     </webServices>
  </scripting>
</system.web.extensions>

Вот так выглядит код моей страницы

<%@ Page Language="C#" EnableViewState="false"  %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="head" runat="server">
    <title>Add ASP.NET User Control dynamically with JQuery</title>
    <script language="javascript" type="text/javascript"   src="Scripts/jquery-1.2.6.pack.js"></script>
    <style type="text/css">
        body
        {
            width:95%;
            padding-left:20px;
            font-family:Arial;
            font-size:10pt;
            padding-right:20px;
        }
    </style>
</head>
<body>
    <form id="form" runat="server">
        <input type="button" value="Load GridView" onclick="getData('ScriptService.asmx/GetControlHtml','~/Controls/GridView.ascx');" />
        <input type="button" value="Load Login Control" onclick="getData('ScriptService.asmx/GetControlHtml','~/Controls/LoginControl.ascx');" />
 <div id="testDiv"></div>
    </form>
<script type="text/javascript">
…     
</script>
</body>
</html>

JavaScript для вызова веб-метода и динамического добавления пользовательского контрола на страницу

function getData(serviceURL, controlLocation) {
 $.ajax({
  type: "POST",
  contentType: "application/json; charset=utf-8",
  dataType: "json",
  url: serviceURL,
  data: "{'controlLocation':'" + controlLocation + "'}",
  success:
   function(msg){
     $('#testDiv').html(msg.d);
   },
  error:
   function(XMLHttpRequest, textStatus, errorThrown){
       alert( "Error Occured!" );
   }
 });
}

Для товарищей, малознакомых с JQuery (к коим отношусь пока и я), хочу объяснить следующую строку javascript-кода

$('#testDiv').html(msg.d);

Собственно в этой строке и происходит все чудо, а именно нам возвращается некий JSON-объект (msg), содержащий в себе строку. Часть строки $(‘#testDiv’) вернет нам набор объектов с id=’testDiv’ (в нашем случае это будет один div), далее мы вызываем метод html, который превратит нашу строку в дерево объектов и поместит его в коллекцию дочерних элементов нашего div’a. Эту операцию можно было записать несколько иначе:

$("#someElement")[0].innerHTML = msg.d;

Возможно, такая запись для кого-то будет понятней.

Данный пример доступен для скачивания. Исходные коды на C#.

Текущий рейтинг: 5.0 (7 голосов)

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


How To: Вызвать Javascript функцию после обновления UpdatePanel

clock апреля 7, 2008 16:45 by author paul

UpdatePanel - это контрол Microsoft ASP.NET AJAX, который позволяет довольно удобно интегрировать AJAX в ваше приложение. Но именно ввиду его удобства и простоты использования со стороны разработчика, некоторые вещи далеко не очевидны. К примеру как вызвать клиентский JavaScript по завершению очередного обновления этой панели?

Трюк заключается в том, чтобы добавить EndRequestHandler в request manager:

Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);

Вот пример формы с двумя TextBox, куда вы вводите текст, а сервер возвращает длину текста и отображает ее во втором TextBox:

<%@ page language="C#" autoeventwireup="true" codebehind="DemoJScriptUpdate.aspx.cs" inherits="CharterWeb.DemoJScriptUpdate" %>
 
 <script runat
="server">
 protected void txtDataOnChange(object sender, EventArgs e) {
 txtLength.Text = txtData.Text.Length.ToString();
 }
 </script>
 <html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>">
 <head id="Head1" runat
="server">
 
 
 <script type="text/javascript">
 function EndRequestHandler(sender, args) {
 if (args.get_error() == undefined)
 alert("Your text has: " + document.getElementById("txtLength").value + " character(s)");
 else
 alert("There was an error" + args.get_error().message);
 }
 function load() {
 Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);
 }
 </script>
 
 <form id="form1" runat
="server">
 <?xml:namespace prefix ="" asp /></asp:scriptmanager id="_scriptManager" runat="server">
 
 <asp:updatepanel id="UpdatePanel1" runat
="server">
 <contenttemplate>
 Write something: </asp:textbox id="txtData" runat="server" autopostback="true" ontextchanged="txtDataOnChange">
 <br />
 Server says the length is: </asp:textbox id="txtLength" runat="server" autopostback="true">
 </contenttemplate>
 </asp:updatepanel>
 
 </form> 

Текущий рейтинг: 4.9 (7 голосов)

  • Currently 4,857143/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


xhtmlConformance mode="Legacy" vs ASP.NET AJAX

clock апреля 2, 2008 16:42 by author paul

 Проблема:

Недавно у меня возникла проблема: после добавления контрола PowerWeb Zoom на страницу, напрочь отказывался работать AJAX. Оказалось этот контрол добавляет в Web.config следующую строчку для корректной работы своих JavaScriptов

<configuration>

    
<system.web>
        
<xhtmlConformance mode="Legacy" />
    </
system.web>


</configuration>

Объяснение:

При разработки еще ранних версий VS 2005 считалось что большинство приложений будут совместимы с XHTML, но для обратной совместимости решили оставить режим "Legacy" (non-XHTML формат страниц, аналогично страницам в ASP.NET 1.1). Иногда подобное изменение приводит и к изменению внешнего вида страниц.

Решение:

Добиться того, чтобы приложение отображало свои страницы в non-XHTML формате и при этом умело работать с асинхронными страницами невозможно, поэтому вам необходимо будет выбрать что-то одно. Хотя в некоторых случаях вы можете попробовать изменить режим на Transitional mode (XHTML Transitional) или на Strict mode (XHTML Strict).

В помощь вам будет список подобных "ловушек" при использовании AJAX, Visual Studio 2005, работы с данными и тп.

Текущий рейтинг: 5.0 (6 голосов)

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Search


LinkedIn Profile

Tags

Posts

  • http://tvsh2004.narod.ru/gm03.html
    test

  • конечно это очень дорого, у нас ведь вся страна пользуется только лицензионной windows...
    Славян

  • Алексей: С удовольствием!
    Подлипенский Павел

  • Присоединяйтесь к ЖЖ-коммьюнити http://community.livejournal.com/ua_extjs
    Алексей

  • Поправка насчет генерации самого хтмл-кода для ответа веб метода. Предлагаю сделать проще, не создавая объекта страницы и без тега <form> [WebMethod] public string GetControlHTML(string controlLocation) { HtmlTextWriter tw = new HtmlTextWriter(new StringWriter()); var uc = (UserControl)(new UserControl()).LoadControl(controlLocation); uc.RenderControl(tw); return tw.InnerWriter.ToString(); }
    Anthony

  • @r-jay там же еще ++
    Dima Pasko

Categories

Calendar

<<  Март 2010  >>
воповтсрчепясу
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910

Archive

© Copyright 2010

Sign in

Ó÷àñòíèê ïëàíåòû Developers.org.ua

Bookmark and Share

Web Developement Blogs - Blog Catalog Blog Directory