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

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

Скажен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


Быстрые веб-страницы: Уменьшаем количество файлов загружаемых браузером

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

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

AppTurns - число файлов ресурсов, требуемых страницей. Они включают файлы CSS, JS, изображений и любые другие файлы, извлекаемые обозревателем в процессе визуализации страницы. Уравнение учитывает страницу HTML отдельно, добавляя время приема-передачи (round-trip time – RTT) перед выражением AppTurns.

Использование множества CSS- и JS-файлов небольшого размера, является хорошей практикой с точки зрения удобства в разработке веб-приложения. Но плохо, с точки зрения производительности вашего приложения. Каждый запрос к серверу требует определенных ресурсов как браузера, так и самого сервера: ожидание в очереди в браузере, время на инициализацию и отправку запроса, передача соответствующих заголовков и cookies, время на обработку запроса и формирования ответа. Время, необходимое для обработки/формирования запроса, называется latency(серенькая область на рисунках ниже). Каждый ресурс, помещенный в отдельный файл, будет бесцеремонно занимать это драгоценное для клиента время.

podlipensky.com without combiner

Поэтому имеет смысл объединять однотипные файлы ресурсов в один. Таким образом, мы экономим на этот самом latency каждого файла ресурсов.

podlipensky.com with combiner

Так как мы говорим о CSS или JS коде, то объединение будет представлять собой конкатенацию строк. Проще всего написать HttpHandler, который бы смог объединять файлы ресурсов в runtime режиме, оставляя разработчику возможность оперировать множеством файлов. При этом не стоит забывать о таких способах оптимизации как GZIP и кэширование ваших ресурсов. Код такого HttpHandler'a может быть таким:

   1: public void ProcessRequest (HttpContext context) {
   2:         
   3:         HttpRequest request = context.Request;
   4:         
   5:         // Читаем параметры: имя ключа в конфиге(содержит список файлов для объединения), тип конетнат и версию конента. 
   6:         //Все эти поля обязательны, т.к. они используются как ключ для кэширования.
   7:         string setName = request["s"] ?? string.Empty;
   8:         string contentType = request["t"] ?? string.Empty;
   9:         string version = request["v"] ?? string.Empty;
  10:  
  11:         // Определяем, позволяет ли браузер сжатие контента
  12:         bool isCompressed = DO_GZIP && this.CanGZip(context.Request);
  13:  
  14:         // Ответ формируем в UTF8 кодировке
  15:         UTF8Encoding encoding = new UTF8Encoding();
  16:  
  17:         // Если ресурс есть в кэше, то берем из кэша.
  18:         // В противном случае, считываем файлы, объединяем и кладем в кэш
  19:         if (!this.WriteFromCache(context, setName, version, isCompressed, contentType))
  20:         {
  21:             using (MemoryStream memoryStream = new MemoryStream(5000))
  22:             {
  23:                 // Определяем тип потока, в который будем писать результат
  24:                 using (Stream writer = isCompressed ?
  25:                     (Stream)(new GZipStream(memoryStream, CompressionMode.Compress)) :
  26:                     memoryStream)
  27:                 {
  28:  
  29:                     // Загружаем файлы, основываясь на ключе в <appSettings>
  30:                     string setDefinition = 
  31:                         System.Configuration.ConfigurationManager.AppSettings[setName] ?? "";
  32:                     string[] fileNames = setDefinition.Split(new char[] { ',' }, 
  33:                         StringSplitOptions.RemoveEmptyEntries);
  34:                     string delimeter = "\r\n";
  35:                     foreach (string fileName in fileNames)
  36:                     {   
  37:                         //Добавляем разделитель, чтобы в двух соседних файлах не произошло объединения ключевых слов.
  38:                         byte[] bytes = encoding.GetBytes(delimeter);
  39:                         writer.Write(bytes, 0, bytes.Length);
  40:                         
  41:                         string text = GetFileText(context, fileName.Trim(), encoding);
  42:                         byte[] fileBytes = encoding.GetBytes(text);
  43:                         writer.Write(fileBytes, 0, fileBytes.Length);
  44:                     }
  45:  
  46:                     writer.Close();
  47:                 }
  48:  
  49:                 //Кэшируем результат
  50:                 byte[] responseBytes = memoryStream.ToArray();
  51:                 context.Cache.Insert(GetCacheKey(setName, version, isCompressed),
  52:                     responseBytes, null, System.Web.Caching.Cache.NoAbsoluteExpiration,
  53:                     CACHE_DURATION);
  54:  
  55:                 // Генерируем ответ
  56:                 this.WriteBytes(responseBytes, context, isCompressed, contentType);
  57:             }
  58:         }
  59:     }

Функция GetFileText читает содержимое файла и возвращает его в виде строки (ввиду простоты функции, я не стал приводить листинг ее кода).

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

Image Map‘ы объединяют несколько картинок в одну большую. Общий объем такой картинки примерно равен сумме объемов маленьких картинок, но уменьшение количества запросов к серверу сокращает общее время загрузки страницы. Image Map будет работать, если картинки на странице находятся рядом друг с другом, например в случае полосы навигации. Определение координат для Image Map’ов — занятие довольно утомительное и зачастую приводит к ошибкам (вообще-то для этого есть специальный софт, однако ничего не могу сказать про качество его работы).

CSS-спрайты являются предпочтительным методом сокращения количества запросов на сервер. Объедините все картинки веб-страницы в одну большую картинку и используйте CSS-свойства для отображения нужного участка картинки.

Inline-картинки используют URL-схему data: для встраивания картинки в саму страницу. Это, однако, увеличит размер HTML-документа. Встраивайте inline-картинки в ваши (кешированные) таблицы стилей — и вы добьетесь уменьшения запросов к серверу, а размер HTML останется прежним.

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

Быстрые веб-страницы: Формирование страницы из нескольких источников

Быстрые веб-страницы: Сжатие и Очистка веб-страниц

Performance Research, Part 6: Less is More — Serving Files Faster by Combining Them

Combine JavaScript with ASP.NET Web forms

CSS Sprites: What They Are, Why They’re Cool, and How To Use Them

 

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

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


Быстрые веб-страницы: Формирование страницы из нескольких источников

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

Недавно мы рассмотрели механизмы оптимизации размера страницы. Следующим нашим объектом оптимизации будет пропускная способность сервера.

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

Зачастую, мы ложим статический контент (картинки, javascript, css-код) в тот же самый веб-проект или веб-сайт. Это приводит к тому, что эти ресурсы скачиваются браузером с одного домена. Такой подход может привести к следующим проблемам:

  • Все ресурсы создают подключения к вашему домену. Поэтому другие, более важные запросы (например запросы к веб-сервису) не могут быть осуществлены, т.к. браузер может создать только два подключения к одному домену.
  • Если вы используете ASP.NET Forms Authentication, то гигансткий Forms Authentication cookie будет посылаться с каждым запросом на ваш домен. Эти cookie будут отправляться при запросе картинки, css-кода или javascript файла, хотя все эти ресурсы, зачастую, не нуждаются в cookie.
  • Такой подход также увеличит размер IIS лога, т.к. он сохраняет cookie для каждого запроса вашего статического контента. Больше того, если вы используете Google Analytics, то к вашим cookie прибавятся еще и четыре больших cookie от компании Google.

Давайте рассмотрим первую проблему более детально

image_thumb

Этот график показывает, что одновременно закачиваются только два файла. Все это происходит только для одного домена. Обратите внимание на загрузку скрипта. Браузер ничего не закачивает параллельно со скриптом. Это объясняется особенностью браузеров в обработке тэга <script>. Таким образом, закачка следующих ресурсов начнется только после завершения закачки и выполнения скрипта.

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

image_thumb_3

Как видите, время загрузки уменшилось примерно на 40%. Помимо графики, мы можем загружать подобным образом CSS и Javascript-код.

Другая проблема, возникающая при загрузке статического контента с того же домена – это огромные Forms Authentication и Google Analytics cookie:

podl

 

 

Таким образом дополнительные 2-3 килобайта будут сопровождать каждый запрос к вашему домену. А оно вам надо?

Решить данну проблему можно двумя способами. Первый, и самый неудобный – располагать статический контент в другом домене и сразу ссылаться на него, при разработке проекта. Второй, более приемлемый – написать свой HttpFilter. Этот фильтр будет просматривать содрежимое сраницы, перед отправкой контента пользователю, выявлять href/src атрибуты и прибавляет к ним некий префикс. Скажем если у меня на странице есть следующий код:

   1: <img src="\images\myphoto.jpg" alt="my photo" />

То фильтр может его трансформировать в следующее:

   1: <img src="http://images.podlipensky.com/myphoto.jpg" alt="my photo" />

После чего вам необходимо будет создать Url Rewritting модуль (или воспользоваться встроенным в IIS 7), который будет изменять url на свой прежний эквивалент. Для высоконагруженных систем, особенно если они оперируют в основном статическим контентом (например видео- или фото- галлереи) полезно действительно размещать этот контент на других серверах. В этом случае можно еще подключить новую фичу IIS 7 – Application Request Routing. Либо воспользоваться Content Delivery Network сервисом.

Впрочем, все вышеописанные методы не новы, и давно используются в коммерческих проектах. Пример подобных оптимизаций, с хорошо описанными исходными кодами, вы сможете найти у Omar AL Zabir’a(который любезно разрешил мне воспользоваться диаграммами, приведенными выше).

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

Smart caching for websites and blogs

IIS URL Rewriting and ASP.NET routing

Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5

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

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


Быстрые веб-страницы: Сжатие и Очистка веб-страниц

clock октября 13, 2008 08:33 by author Подлипенский Павел

Несмотря на стремительное развитие интернета, проблема оптимизации веб-приложений стоит также остро, как и во времена dialup-подключений по советской вермишели.

В сентябре 2006 года Питер Севчик (Peter Sevcik) и Ребекка Ветцель (Rebecca Wetzel) из компании NetForecast опубликовали документ, именуемый "Field Guide to Application Delivery Systems" («Полевое руководство по системам доставки приложений»). Основное внимание в документе было уделено улучшению производительности приложений в глобальных сетях (wide area network – WAN), и в нем было приведено уравнение

yrav , где

  • R - время ответа. Общее время с запроса страницы пользователем (обычно переходом по ссылке и т.п.) до полной визуализации страницы на его компьютере. Обычно измеряется в секундах.
  • Полезная нагрузка - общее число байтов, отправленных обозревателю, включая разметку и все ресурсы (такие как файлы CSS, JS и изображений).
  • Пропускная способность - скорость передачи данных обозревателю и от него. Может быть асимметрична и представлять несколько скоростей, если данная страница создается из нескольких источников. Обычно усредняется для создания единого выражения пропускной способности в байтах в секунду.
  • AppTurns - число файлов ресурсов, требуемых страницей. Они включают файлы CSS, JS, изображений и любые другие файлы, извлекаемые обозревателем в процессе визуализации страницы. Уравнение учитывает страницу HTML отдельно, добавляя время приема-передачи (round-trip time – RTT) перед выражением AppTurns.
  • RTT - время, необходимое для приема и передачи данных, вне зависимости от числа переданных байтов. Каждый запрос тратит минимум одно RTT для самой страницы. Обычно измеряется в миллисекундах.
  • Cs - время вычислений на сервере. Время, уходящее у кода на запуск, извлечение данных из базы данных и составление ответа, отправляемого обозревателю. Измеряется в миллисекундах.
  • Cc - время вычислений на клиенте. Время, уходящее у обозревателя на визуализацию HTML на экране, исполнение JavaScript, применение правил CSS, итд.

Этот пост будет началом серии статей по оптимизации производительности вашего веб-приложения.

Рассмотрим первый параметр, влияющий на время загрузки страницы – полезная нагрузка или объем полезных данных.

Архивирование(сжатие) контента страницы

Первое, что мы можем сделать - это сжать наш html, css и js код с помощью GZip или Deflate(~40% лучше, чем gzip) сжатия. Не все браузеры принимают сжатый контент, поэтому необходимо проверять, содержит ли запрос заголовок Accept-Encoding со значением “gzip” или “deflate”:

   1: private bool CanGZip(HttpRequest request) 
   2: { 
   3:         string acceptEncoding = request.Headers["Accept-Encoding"]; 
   4:         if (!string.IsNullOrEmpty(acceptEncoding) && 
   5:              (acceptEncoding.Contains("gzip") || acceptEncoding.Contains("deflate"))) 
   6:             return true; 
   7:         return false; 
   8: }

Программно сжать контент позволяет пространство имен System.IO.Compression

   1: public static byte[] Compressor(byte[] buffer, string encodingType) 
   2:      { 
   3:          using (MemoryStream memStream = new MemoryStream()) 
   4:          { 
   5:              Stream compress = null; 
   6:  
   7:              // Choose the compression type and make the compression 
   8:              if (String.Equals(encodingType, "gzip", StringComparison.Ordinal)) 
   9:              { 
  10:                  compress = new GZipStream(memStream, CompressionMode.Compress); 
  11:              } 
  12:              else if (String.Equals(encodingType, "deflate", StringComparison.Ordinal)) 
  13:              { 
  14:                  compress = new DeflateStream(memStream, CompressionMode.Compress); 
  15:              } 
  16:              else 
  17:              { 
  18:                  // No compression 
  19:                  return buffer; 
  20:              } 
  21:  
  22:              compress.Write(buffer, 0, buffer.Length); 
  23:              compress.Dispose(); 
  24:  
  25:              return memStream.ToArray(); 
  26:          } 
  27:      } 

После чего вам остается лишь добавить сжатый поток в ответ пользователю:

   1: HttpContext.Response.OutputStream.Write(compressedData, 0, compressedData.Length);

Если же у вас есть доступ к IIS консоли, то вы можете настроить сжатие на уровне IIS(версии 7):

iis_compression1 

iis_compr2

Очистка JS и CSS кода

Также мы можем очистить наш css и js код от лишних символов.

Например, следующий css код

   1: body {
   2:   font-size:14px;
   3:   font-family:Arial;
   4: }
   5: h1 {
   6:   font-size:14px;
   7:   font-family:Arial;
   8: }

можно преобразовать в следующую строку

   1: body,h1{font:14px arial}
 

Основной принцип подобных алгоритмов – это превращение человеко-читемого кода в сжатый код понятный лишь компилятору.

Для javascript кода наибольшей популярностью пользуются два инструмента JSMin (автор: Douglas Crockford) и Packer (автор: Dean Edward). Алгоритмы упаковки обоих инструментов обрабатывают(obfuscate) любой js код, но только при условии, что вы корректно завершаете все javascript-выражения символом “;” (включая объявление функций).

Для css кода вы можете воспользоваться утилитой под названием CSSTidy или одним из множества подобных онлайн-сервисов.

Оптимизация графики

Допустим в вашей базе данных, на жестком диске или любом другом хранилище расположена ваша любимая фотография размером 200x400 пикселей (24 Kb). Но вам необходимо отобразить ее на странице в виде изображения размером 100х200 пикселей. В таком случае, подобный код

   1: <img src="/images/mybestphoto.png" width="100" height="200" alt="My Best Photo" />

решит вашу проблему, но при этом размер вашей фотографии останется прежним - 24 Kb. Хотя, если бы вы сжали(изменили размер) ее в фотопопе, то "вес" файла существенно бы уменьшился.

Для того, чтобы достичь подобного эффекта, вам необходимо программно, на сервере сжать вашу графику. Примерно таким образом:

   1: public void SaveResizedImage(string imagePath, int width, int height)
   2: {
   3:         int newResizeimageId;
   4:         // Читаем графический файл с жесткого диска
   5:         FileStream fs = File.OpenRead(imagePath);
   6:         byte[] data = new byte[fs.Length];
   7:         fs.Read(data, 0, data.Length);
   8:         MemoryStream ms = new MemoryStream(data);
   9:         Bitmap bmp = new Bitmap(ms);
  10:         System.Drawing.Image imgPhoto = (Image)bmp;
  11:         // Настраиваем Encoder, для преобразования графики
  12:         Encoder qualityEncoder = Encoder.Quality;
  13:         EncoderParameters parameterList = new EncoderParameters(1);
  14:         EncoderParameter qualityParameter = new EncoderParameter(qualityEncoder, 50L);
  15:         parameterList.Param[0] = qualityParameter;
  16:         // По расширению файла определяем кодек
  17:         ImageCodecInfo codec = GetCodecFromExtension(Path.GetExtension(imagePath)); //GetCodecFromExtension в этом листинге не приведена.
  18:         // Создаем пустую канву. Измененная графика будет записана в эту канву.
  19:         Bitmap bmPhoto = new Bitmap(width, height);
  20:         bmPhoto.SetResolution(10, 10);
  21:         Graphics grPhoto = Graphics.FromImage(bmPhoto);
  22:         grPhoto.SmoothingMode = SmoothingMode.HighSpeed;
  23:         grPhoto.InterpolationMode = InterpolationMode.High;
  24:         grPhoto.PixelOffsetMode = PixelOffsetMode.HighSpeed;
  25:         grPhoto.DrawImage(imgPhoto, new Rectangle(0, 0, width, height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel);
  26:         // Сохраняем файл в память, а затем убеждаемся, что все ресурсы освобождены корректно.
  27:         MemoryStream mm = new MemoryStream();
  28:         bmPhoto.Save(mm, codec, parameterList);
  29:         imgPhoto.Dispose();
  30:         bmPhoto.Dispose();
  31:         grPhoto.Dispose();
  32:         //Сохраняем массив байт измененной графики куда необходимо. 
  33:         newResizeimageId = SaveImageToDb2(mm.GetBuffer());
  34:         mm.Dispose();
  35: }

Хочу обратить ваше внимание на строчку

   1: bmPhoto.SetResolution(10, 10);

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

avatar avatar_0 avatar_2 avatar_5 avatar_8
2.58 kB 2.86 kB (+10%) 1.98 kB
(-23%)
1.55 kB
(-39%)
672 bytes
(-74%)

Обратите внимание на то, что после небольшого ухудшения качества, размер изображения наоборот - возрос. Дальнейшее же уменьшения разрешения привело к уменьшению размера файла. Также учтите, что, чем больше первоначальный размер изображения, тем эффективней будет сжатие без визуальных потерь качества. Ухудшать качество небольших картинок, как видите, смысла нет.

Отключаем ViewState

Возможно вы подумали, о нехитром свойстве страницы EnableViewState="false". Отключение ViewState с помощью вышеупомянутого свойства действительно уменьшит размер скрытого поля, но не избавит вас от него. В отдельных случаях полезно и вовсе избавиться от ViewState. Сделать это можно, переопределив метод SavePageStateToPersistenceMedium, и “забыв” вызвать в нем базовый метод.

   1: protected override void SavePageStateToPersistenceMedium(object state) 
   2: { 
   3:         //base.SavePageStateToPersistenceMedium(state); 
   4: }

Избавляемся от длинных ID, сгенерированных ASP.NET

К сожалению, не существует способа избавиться от длинных ID в debug-версии вашего веб-сайта. Но когда ваш проект уже готов и скомпилирован, то вы можете обработать сборки, обфускатором. При этом, следует указать обфускатору заменять все имена контролов на более короткие. Таким образом вместо ctl00_body_WidgetPanelsLayout_WidgetContainer65_WidgetBodyPanel, ваша панель будет иметь id равное, например А. Будьте осторожны с подобной оптимизацией – ваш javascript код может не работать, если функционал привязан к заранее заданным ID. Хотя, если вы использовали что-то похожее на следующий код

   1: $get('<%= TextBox1.ClientID %>')

то обфускатор не нарушит вашего функционала.

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

Reduce the weight of stylesheets by 35% at runtime

HTTP compression in ASP.NET 2.0

Compression and performance - GZip vs. Deflate

Compress your pages, css, js and WebResources.axd files for better performance

Online Tool compares Packer, JSMin, Dojo, and YUI Compressor

Speed Up Your Site: Optimize your CSS

CSS Optimization: Make Your Sites Load Faster for Free

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

  • 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


Шпаргалки для разработчиков пользовательских интерфейсов

clock августа 18, 2008 08:00 by author Подлипенский Павел
Подобного рода шпаргалки полезны для запоминания синтаксиса языка, визуального представления взаимосвязей и просто украшают ваш офис. Пользуйтесь на здоровье.

HTML/XHTML

1. HTML Help Sheet

HTML Help Sheet Screenshot

2. HTML Cheat Sheet

HTML Cheat Sheet - Screen shot.

3. HTML Character Entities Cheat Sheet

HTML Character Entities Cheat Sheet - Screen shot.

4. XHTML Cheat Sheet v. 1.03 – PDF

XHTML Cheat Sheet v. 1.03 - screen shot.

CSS

5. CSS Cheat Sheet (V2)

CSS Cheat Sheet (V2) - screen shot.

6. CSS Cheat Sheet

CSS Cheat Sheet - screen shot.

7. CSS Shorthand Cheat Sheet

CSS Shorthand Cheat Sheet - screen shot.

8. CSS Level 1 Quick Reference – PDF

CSS Level 1 Quick Reference - screen shot.

9. CSS Level 2 Quick Reference – PDF

CSS Level 2 Quick Reference - screen shot.

10. CSS2.1 Quick Reference Card – PDF

CSS2.1 Quick Reference Card - screen shot.

11. CSS2 Reference Guide – PDF

CSS2 Reference Guide - screen shot.

JavaScript

12. JavaScript Cheat Sheet

JavaScript Cheat Sheet - screen shot.

13. Addison-Wesley’s JavaScript Reference Card – PDF

Addison-Wesley's JavaScript Reference Card - screen shot.

14. JavaScript and Browser Objects Quick Reference

JavaScript and Browser Objects Quick Reference - screen shot.

15. The most common DOM methods at a glance – PDF

The most common DOM methods at a glance - Screen shot.

16. JavaScript Quick Reference Card/Cheatsheet

avaScript Quick Reference Card/Cheatsheet - Screen shot.

17. mootools 1.2 cheat sheet

mootools 1.2 cheat sheet - screen shot.

18. jQuery Cheatsheet

jQuery Cheatsheet - screen shot.

19. jQuery 1.2 Cheat Sheet

jQuery 1.2 Cheat Sheet - screen shot.

20. jQuery Visual Map – PNG

jQuery Visual Map - screen shot.

Miscellaneous

21. RGB Hex Colour Chart

RGB Hex Colour Chart - screen shot.

22. The Web Developer’s SEO Cheat Sheet

The Web Developer's SEO Cheat Sheet - screen shot

23. The WordPress Help Sheet

The WordPress Help Sheet - screen shot.

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

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


Зачем людям PR?

clock августа 17, 2008 20:28 by author Подлипенский Павел

С недавних пор начал интересоваться оптимизацией сайтов не только с точки зрения производительности, но и с точки зрения оптимизации под поисковые машины. Чтож поделаешь, заказчики хотят зарабатывать на рекламе, а я по-прежнему хочу зарабатывать на заказчиках...

Для всех давно не секрет, что такое PR, и с помощью каких систем его можно определить. А все ли знают как он опредляется? Напомню, что PR опредляется не для всего сайта целиком, а для каждой отдельной страницы. При определении PageRank необходимо учесть все внутренние и внешние ссылки на страницу.

Формула опредления:
PR(A) = (1-d) + d(PR(t1)/C(t1) +… + PR(tn)/C(tn)),
где PR(t1…tn) - вес страницы, ссылающейся на страницу A,
C - количество исходящих ссылок со страницы А,
d - коэффициент затухания, обычно принимаемый 0.85.

Из уравнения следует, что одна ссылка со страницы с PR4 и пятью исходящими ссылками передаст больший вес, чем ссылка со страницы с PR8 и сотней исходящих ссылок. Чем больше исходящих ссылок на странице, тем меньший PageRank будет передан по такой ссылке, и это не зависит от того - внешние ли это будут ссылки или внутренние. При этом у страниц отдающих свой "голос" за другие страницы PR не уменьшается!!!

Что делать если у вас много исходыщих ссылок на всех страницах? Неоходимо все ссылки которые только можно - скрывать от поисковых систем. О том как это сделать в ASP.NET хорошо написал Дмитрий.

Согласно вышеуказанной формуле можно делать прогнозы на будущее! Можно самому написать скрипт по пронозу, но зачем делать то - что кто-то уже сделал это раньше… Данный сервис помимо прогноза показывает общее количество бэков на ваш сайт.

Подводя итоги: делайте как можно больше ссылок не только на главную страницу, но также и на остальные внутренние страницы, в своих постах ставьте тематические ссылки на ваши другие (ранее написанные) посты, всё лишнее скрывайте от “глаз” поисковика…

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

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


Search


LinkedIn Profile

Tags

Posts

  • Pingback from 241.akemet.com Cb300 Second Hand Address, Cb3000 Video Price Marine Engines
    241.akemet.com

  • 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

Categories

Calendar

<<  Сентябрь 2010  >>
воповтсрчепясу
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

Archive

© Copyright 2010

Sign in

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

Bookmark and Share

Web Developement Blogs - Blog Catalog Blog Directory