Сегодня вышел Google App Engine 1.5.0. Кроме большого числа пофикшенных багов, появилось несколько достаточно интересных изменений.

Среди них стоит отметить такие:

 

  • Backends - постоянно запущенный инстанс одной из четырех конфигураций, который не связан с запросами (http requests) и может занимать до 1GB памяти. Один из способов применения - генерация отчетов, которая занимает много времени или другие ресурсоемкие задач
  • Изменения в Task Queue - поддержка pull-запросов, увеличение лимита на используемую память
  • Размер HTTP Request и Response увеличен до 32MB
  • High Replication Datastore теперь является хранилищем по умолчанию для новых приложений
  • Много изменений, связанных с квотами - некоторые были увеличены, а некоторые, наоборот - уменьшены
  • К моему сожалению, Full Text Search еще не закончили :(. 

 

 Отдельным пунктом хочу отметить экспериментальную поддержку языка программирования Go. Новости об этом языке, в основном, проходили мимо меня и я только иногда слышал упоминания о нем. Теперь же, когда Google добавил пусть и эксперементальную, но все-же поддержку, то многие захотят посмотреть на него более внимательно. Особенно, учитывая то, что он создан для ресурсо(процессоро)-емких задач будет компилироваться в native code.

Ссылки по теме:

 

 

 

 P.S. Интересно, насколько будет популярен Go в Украине через полгода-год, по сравнению с Python и Ruby?


 

Рассказ о “странном” баге и о том, как влияет верстка работу всего приложения.

При работе с ASP.NET Webforms мы постоянно сталкиваемся с формами. По умолчанию, это одна серверная форма <form id=”aspnetForm” runat=”sever”>, расположенная сразу же за тегом <body>. Но это, можно сказать, классический пример - такую заготовку делает нам Visual Studio при создании другого проекта. На практике же всё может сильно отличаться.

 

Следует отметить, что на странице вы не можете создать более одной серверной формы (с атрибутом runat=”server”). Такое уж ограничение архитектуры ASP.NET. Почему так - догадаться не сложно, но...

 

Но в жизни в проекте бывают ситуации, когда просто необходимо добавить ещё одну форму на страницу. Из достаточно распространённых примеров это: 

 

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

 

Решение данной задачи достаточно простое - добавление второй формы (<form>) на страницу, но уже без атрибута runat=”server”. Следует отметить, что с точки зрения html - несколько форм на одной странице являются абсолютно нормальным и работающем решением. Если только не наступать та те же грабли, на которые наступил я...

 

А допустил я достаточно “детскую” ошибку - т.к. было ограничение на одну серверную форму, то я добавил вторую, клиентскую, внутрь серверной. На первый взгляд всё работало хорошо, обе формы успешно отправлялись на сервер и отправляли все необходимые данные. Вот только работало это в браузерах Google Chrome, Safari и FireFox. Проблемы начались в Opera и Internet Explorer. Выглядело это, на мой взгляд, действительно потрясающе: 

 

Форма фидбека с UpdatePanel двумя TextBox и LinkButton на странице. Обработчик OnClick у кнопки успешно отрабатывал, за исключением того, что значения текстбоксов были пустыми. Дело было вечером и я подумал что проблема в UpdatePanel. Вот только странно было что в IE это тоже не работало. Под нож попала UpdatePanel, что не дало никакого положительного результата. “Странно” - подумал я и проверил это всё ещё раз в разных браузерах. Баг был на месте. Тут пришлось вплотную взяться дебаггером за эту страницу и через некоторое время, внимательно посмотрев на Request.Params причина была обнаружена - сабмитилась не та форма.

 

Дальнейшие танцы с бубном возникшие идеи результата не принесли я на помощь пришел Google:

 

 

Обрадовало меня сразу две вещи:

 

  • такая проблема была не только у меня;
  • причина всего этого безобразия стала ясна уже только при беглом просмотре результатов выдачи гугла - 3-я ссылка вела на сайт W3C, на которой черным по белому было написано: “the FORM element can’t be nested”. (http://www.w3.org/MarkUp/html3/forms.html)

 

 

После этого проблема была быстро решена способом, описанным в начале поста, но мне захотелось ещё немного копнуть внутрь.

 

Тут же был создан небольшой html файл (forms1.html)  и был дан валидатору http://validator.w3.org/. К моему удивлению, валидатор был уверен в том, что html код является полностью валидным. После смены doctype с Transitional на Strict (forms2.html) страница уже оказывалась невалидной. И тут всё окончательно прояснилось и стало на свои места.

 

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

 

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

 

Исходники форм: https://github.com/e0ne/BlogSamples/tree/master/NestedForms

 


Чем дольше пользуюсь NuGet, тем больше интересных вещей с его нахожу. Одной из таких библиотек является elmah. Простота установки, особенно с использованием NuGet, и широкие возможности настройки подойдут к практически любому проекту. Я сам для этого раньше предпочитал использовать Logging модуль из Microsoft Enterprice Library, но сейчас понял что есть более гибкие и современные решения.

Elmah создан специально для того, чтобы логировать ошибки в ASP.NET приложениях.

Среди его функций есть такие:

  • логирование ошибок в различные БД (MS Sql, Oracle, PostgreSQL, SQLite и др.);
  • экспорт логов в формат CSV для последующего анализа;
  • создание RSS-фида для получения информации о новых ошибках;
  • отправление сообщений о новых исключениях прямо в ваш twitter!

Отдельно хочу сказать о логировании ошибок, которые произошли в момент обновления UpdatePanel - иногда это бывает очень полезно.

Если вы всё ещё по каким-то причинам не используете NuGet, то для вас установка будет происходить следующим способом:

  • скачать сборку Elmah.dll (всего 156KB);
  • добавить в ваш веб-проект reference на elmah;
  • последний и самый сложный пункт - внести необходимые изменения в web.config.

Так как elmah работает как обычный web handler, то проблем с ним быть никаких не должно.

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

Для того, чтобы посмотреть последние логи, необходимо открыть следующий URL: http://localhost:8090/elmah.axd. В качестве тестового приложения я создал новый Web Application и посмотрел на логи:

На удивление обнаружил, что в логах уже есть одна 404-я (Not Found) ошибка. Посмотрев на детали исключения сразу становится понятно, что не найден файл favicon.ico.

Для примера, я поместил на страницу кнопку, обработчик OnClick которой бросает исключение:

throw new NotImplementedException();

Посмотрим теперь на нашм логи:

У нас появилась запись с кодом 500 (Server Error) и типом NotImplemented.

В деталях каждой записи кроме времени и текста ошибки хранится полный callstack, все параметры, которые пришли в запросе (Request.Params) и, на мой взгляд самое интересное - ссылка с именем “Original ASP.NET error page”. Перейдя по ней можно посмотреть как выглядела страница, когда произошла ошибка. Таким образом можно увидеть что показывалось пользователю, когда это случилось.

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

На этом мой короткий обзор закончен. Более детально об elmah можно прочитать на официальной странице (http://code.google.com/p/elmah/). Моей целью не было написать полный и подробный обзор-руководство по этой очень удобной и полезной библиотекой. Цель этого поста - всего-лишь познакомить с elmah тех читателей, которые еще не слышали о ней.

P.S. Для самых ленивых выложил тестовый проект на GitHub: https://github.com/e0ne/BlogSamples/tree/master/ElmahSampleProject


При написании кода на языке C# достаточно часто приходится использовать конструкцию foreach. Ведь так на много удобнее проходить по коллекциям, по сравнению с использованием цикла for. Безусловно, у каждого метода есть свои плюсы и минусы и выбор всегда зависит от конкретной задачи и ситуации. Но на днях меня удивила одни интересная особенность конструкции foreach, а  именно то, как это работает.

Рассмотрим простой пример:

У нас есть некая коллекция элементов и с помощью foreach мы выводим на консоль имена всех элементов.

При этом класс MyCollection выглядит так:

Класс коллекции реализовывает единственный метод GetEnumerator интерфейса IEnumerable для возможности использования класса в конструкции foreach.

Особенности enumerator’а нас сейчас не интересуют, будем считать что он работает так, как ему положено.

Теперь сделаем простую вещь, а именно, поменяем наш класс MyCollection так, чтобы он больше не реализовывал интерфейс IEnumerable, при этом метод GetEnumerator оставим без изменений.

К моему удивлению, код и дальше продолжил компиляцию и правильно работал. Первым делом, посмотрим какой IL-код у нас получился:

Тут хорошо видно, что при создании IL-кода компилятор не обращает внимания на наличие интерфейса IEnumerable, а непосредственно вызывает метод GetEnumerator. На этом моменте мне стало интересно и я пошел читать спецификацию языка C# (Standard ECMA-334 C# Language Specification), которая, к слову, датирована далёким июнем 2006-го года.  В разделе 8.18 Итераторы сказано следующее:

The foreach statement is used to iterate over the elements of an enumerable collection. In order to be
enumerable, a collection shall have a parameterless GetEnumerator method that returns an enumerator.
Generally, enumerators are difficult to implement, but the task is significantly simplified with iterators.

Таким образом, получается что для использования коллекции в конструкции foreach достаточно только метода GetEnumerator, а наличие интерфейса - необязательное условие.

Пример кода доступен по адресу: https://github.com/e0ne/BlogSamples/tree/master/ForeachTest


Со времен ASP.NET 1.1, по умолчанию, у всех страниц свойство ValidateRequest было равно true. Это означает, что при вводе в поле ввода определенные спецсимволы (пример: <,>,&,#)  и отправки формы на сервер мы успешно получим HttpRequestValidationException.

Непонятное, на первый взгляд, поведение объясняется достаточно просто - защита от XSS атак. XSS (cross site scripting) - один из типов атак на веб-сайт, целью которой является вставка (инъекция)  чужого javascript-кода на атакуемый сайт. Результатами такой атаки могут быть от показа пользователю ненужных ему сообщений, до кражи cookie и перенаправления на другой сайт, который может содержать вредоносный код. Пример такой ситуации можно посмотреть в XssSample.aspx.

Но так как в определённых ситуациях должна быть возможность ввести любой символ, то приходится отключать request validation. Для предотвращения XSS-атаки при отображении пользователю введенного текста необходимо экранировать специальные символы с помощью метода Server.HtmlEncode(). Пример кода находится в AntiXssSample.aspx.

На первый взгляд, кажется что всё просто и понятно. Но есть некоторые нюансы:

  • необходимо помнить о том, что request validation отключен и нужно экранировать весь введенный пользователем текст во все поля (помним правило: никогда(!) не доверять данным, которые ввёл пользователь);
  • если используется Server.HtmlEncode(), то помним, что есть ещё “обратный” метод Server.HtmlDecode();
  • можно не отключать request validation и экранировать все введенные данные на стороне клиента с помощью javascript, но при этом не забывать о валидации (проверки) данных на сервере.

В целом, при правильном подходе никаких проблем с отключением request validation не должно быть, но всегда необходимо помнить о безопасности.

Ещё стоит отметить то, что механихм request validation немного поменялся в ASP.NET 4. Теперь он, по умолчанию, проверяет не только запросы к aspx страницам, но и все остальные запросы к серверу. Отключить это можно в web.config таким способом:

<httpRuntime requestValidationMode="2.0" />

Ссылки по теме:

Ссылка на пример: https://github.com/e0ne/BlogSamples


1. Введение
2. Обзор framework'а
3. Жизненный цикл страницы
4. Полезные объекты и функции

1. Введение

В предыдущем посте из этой серии (ASP.NET Ajax. Часть 1: что внутри?) я рассказал что такое AJAX и как Microsoft помогает нам его использовать. Сегодня я более подробно расскажу о его клиентской части. Частично из-за того, что эту информацию не так просто найти в MSDN, как хотелось бы, частично  из-за того, что в последнее время Microsoft уделяет этой части всё меньше внимания, агитируя использовать jQuery, многие разработчики даже на догадываются какой мощных инструмент находится у них в руках.

2. Обзор framework'а

По умолчанию, эти скрипты грузятся на страницу, на которой есть ScriptManager по ссылке вида ScriptResource.axd?d=scriptIdentificator. Сами же скрипты находятся в ресурсах сборки System.Web.Extensions (если у кого-то всё-ещё установлена VS2005, то эти скрипты можно найти в папке c:\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\v1.0.61025\MicrosoftAjaxLibrary\System.Web.Extensions\). Также можно загружать эти скрипты с помощью CDN. Подробнее об этом способе можно почитать тут.
Сам скирт немного отличается для WebForms и ASP.NET MVC, но ядро у них общее.
Все функции/объекты разделены на пространства имён (namespaces) по аналогии с серверной частью. Перечислять я их не буду, так как на MSDN (http://msdn.microsoft.com/en-us/library/bb397536.aspx, http://msdn.microsoft.com/en-us/library/dd410060.aspx) всё хорошо описано.

3. Жизненный цикл страницы

Кроме стандартных для DOM модели событий, ASP.NET Ajax предоставляет нам  доступ как к событиям всего приложения (init, load, unload и др.), так и события, связанные с запросами на сервер (beginRequest, endRequest и др.). Как всегда, за полной информацией лучше обратиться в первоисточник, а именно - http://msdn.microsoft.com/en-us/library/bb386417.aspx.

4.Полезные объекты и функции

MS Ajax Library предоставляет нам как новые типы/функции, так и расширения для стандартных - Array, Number, Date, String и др., о которых можно почитать в MSDN Magazine (http://msdn.microsoft.com/en-us/magazine/cc163300.aspx).
Одними из наиболее частоиспользуемых являются функции $get() и $find():
- $get()  - оптимизированный по производительности аналог document.getElementById, который ищет элемент по его ID и в качестве второго параметра может принимать parent-элемент, в котором нам необходимо найти нужный элемент DOM-модели.
- $find() - функция, которая очень похожа на $get(), но возвращает не DOM-элемент, а экзепмляр Ajax Client Control.
Более детальное описания использования этих функций: http://mattberseth.com/blog/2007/08/the_everuseful_get_and_find_as.html


В декабре прошлого года я написал пост по названием “Программирование на .NET: С чего начать?” на тему того, чтобы почитать начинающим разработчикам на платформе .NET. С того момента прошло достаточное количество времени и могло появиться желание или необходимость, начать писать веб-приложения на основе технологиеи ASP.NET. Не важно, будет это ASP.NET Webforms или ASP.NET MVC - в любом случаем, знание одной технологии не мешает познакомиться с другой. Далее я приведу список книг/блогов, которые рекомендую для знакомства с веб-разработкой на основе .NET Framework.

  • Начну с книги Дино Эспозито “Introducing Microsoft ASP.Net 2.0” - отличное введение в ASP.NET 2.0. Несмотря на то, что этот замечательный автор уже написал книгу по ASP.NET 3.5, эта книга не теряет соей актуальности и служит отличным введением в мир веб-разработки на основе технологий от Microsoft.
  • Книга “Programming Microsoft ASP.NET 3.5" является хорошим продлолжением предыдущей и не нуждается в комментариях. Добавлю лишь одно: некоторые считают что эти две книги все-равно что книга Дж. Рихтера CLR via C#.
  • Marco Bellinaso, “ASP.NET 2.0 Website Programming: Problem - Design - Solution” - книга, которая почетное место на моей книжной полке. Книга описывает процесс создания сайта под названием BeerHouse Project от начала и до конца. Если что-то непонятно, то всегда можно посмотреть исходники этого проекта. Отличная книга для начинающих, чтобы познакомиться с процессом создания сайта от начала и до конца.
  • Следующая книга от сразу двух авторов Matthew MacDonald и Adam Freeman имеет название “Pro ASP.NET 4 in C# 2010”. Я читал более старое название про ASP.NET 2.0. В книге достаточно подробно описывается технология ASP.NET, но читать ее нужно когда базовые знания уже есть.

Технология ASP.NET MVC более молодая и выбор книг значительно меньше. Большинство из них написаны про первую версию этого фреймворки и из-за значительных изменений настоятельно рекомендую читать книги по актуальной на сегодняшний день версии 2.0.
Это такие книги, как:

  • "Pro ASP.NET MVC 2 Framework" от Steven Sanderson - очень подробно и понятно написаны как основы, так и достаточно продвинутые вещи о ASP.NET MVC.
  • "ASP.NET MVC 2 in Action" ) от сразу пяти авторов. Если коротко, то я еще не встречал ни одной книги из этой серии, которая бы меня не заинтересовали и после прочтения которой я бы пожалел о потраченном времени.
  • Еще есть книга “ASP.NET MVC Framework” по ASP.NET MVC 2.0 от русских авторов Гайдара Магданурова и Владимира Юнева. Т.к. книгу только пролистал на балке, то никаких комметариев о ней писать не буду за исключением того, что она вполне годиться для введения в данную технологию.

С книгами закончили, теперь пройдемся по списку веб-ресурсов, RSS которых я регулярно читаю:

  • Сайт http://www.asp.net/ от Microsoft. Название говорит само за себя. Отличный ресурс с форумами, блогами, вики, ссылками на различные opensource приложения. Отдельно хочу выделить раздел с обучающим видео. Это лучше увидеть самому! Единственным их недостатком является то, что они могут ввести в ошибочное заблуждение, что разработка любого сайта - очень и очень простое занятие. В остальном - обязательно смотреть начинающим веб-разработчикам.
  • http://weblogs.asp.net/scottgu/ - блог Скота Гатри. Его должность решил не переводить, а процитировать с его блога:
    "My name is Scott Guthrie, and I am a Corporate Vice President in the Microsoft Developer Division. I run the development teams that build the following products/technologies: CLR and the core .NET Base Class Libraries, ASP.NET, Silverlight, WPF, IIS 7.0, Visual Studio Tools for ASP.NET, WPF, Silverlight and Mobile". Отличные технические посты о самых новых технологиях! Очень часто после публикации очередного поста проходит не одна неделя/месяц до того, как очередная технология/приложение станет доступным для разработчиков.
  • http://dev.net.ua/ и http://msug.vn.ua/ - сайты харьковской и винницкой .NET User Group - не только об asp.net, но и о других технологиях Microsoft.
  • http://www.nikhilk.net/ - Nikhil Kothari's Weblog - блог разработчика из Microsoft, посвященный веб-технологиям.
  • И последнее: MSDN - без него сложно представить жизь разработчика.

Продолжение следует. В следующем посте из серии для начинающих (веб)разработчиков я расскажу о том, что необходимо знать любому разработчику на платформе ASP.NET.


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

Ситуация была довольно таки простая: есть некий wizard, шаги которого хранятся в поле типа Stack для удобного перемещения вперёд-назад. Естественно, в зависимости от текущего номера шага, нужно было выполнять определённые действия. И вот, после очередного багфикса, пришлось с помощь дебаггера разбираться что же там происходит... Но, при дебагге время от времени (в начале мне было абсолютно непонятно из-за чего это происходит) я получал: System.InvalidOperationException: Stack empty. И это при том, что без дебаггера всё работало! Чтоб разобраться в чем дело, я решил написать маленькое консольное приложение (исходники, как всегда, прикреплены к посту), которое состояло из объявления стека, его наполнения и свойства класса StackItem:

 

Те, кто сталкивался с этим раньше, наверное, уже поняли в чем проблема. Запускаем дебаггер, и после наполнения стека смотрим значения свойства StackItem:

 

Второй раз смотрим значения свойства StackItem:

И здесь произошло самое интересное: при просмотре значения свойства дебаггер выполняет весь код, который находится в конструкции get. Таким образом, при каждом просмотре зачения свойства StackItem, в нашем стеке находилось все меньше и меньше данных. Возможно, для кого-то этот подход и является вполне логичным и очевидным, но не для меня. Ведь могли же в Microsoft предусмотреть это? Но нет, теперь у нас есть такая фича дебаггера, или баг...

А пока, для дебагга подобного кода, приходится использовать конструкцию вида:

 

В этом случае, если переменной i не присвоить другого значения, но она всегда будет хранить в себе число 5.

P.S. Проверял как в VS2008, так и в VS2010. Скорее всего, это фича такая...

DebuggerTest.rar (2.74 kb)


В прошлую пятницу прошла очередная встреча юзер-группы UNETA, На которой я делал доклад на тему "Введение в DLR" и затронул тему IronPython. Надеюсь, что вскоре найду время и напишу несколько более детельных постов на эту тему.

P.S. Для запуска проекта необходима Visual Studio 2010 и IronPython 2.6.1. Также использовалась библиотека json.codeplex.com/.

Introducing_to_DLR.ppt (352.00 kb)

IntroducingToDLR.rar (2.25 mb)


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

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

Реализация интерфейса IScriptControl, который состоит из 2-х методов, помагает реализовать нужную задачу в несколько строк кода (не считая, конечно-то ещё нескольких строчек на JavaScript).

 

 

  • В методе GetScriptDescriptors() мы создаём дескрипторы в которых говорим какие клиентские свойства должны быть у контрола.
  • Метод GetScriptReferences() возвращает список клиентских скриптов, которые нам нужны и будут автоматически загружены с помощью ScriptManager.
С серверной стороной мы практически закончили, осталось только добавить несколько строк в обработчики событий OnPreRender и Render:

 

С серверной стороной закончили. Теперь осталось совсем немного написать на JavaScript. Как всегда, большую часть за нас сделала Microsoft. Добавляем в проект js-файл типа AJAX ClientControl:

Для нас создастса уже готовый прототик контрола, где нам останется только объявить все наши свойства, getters & setters для них, события и методы. 

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

Хочу заметить, что всё описанное выше без каких-либо изминений можно применять только для WebControl. Если же нужно сделать UserControl, то в нём нужно поместить какой-либо контейнер (e.g. <div id="container" runat="server"></div>) и при создании дескрипторов указывать ID контейнера, иначе вы получите клиентскуб ошибку что не к сему привязать js объект.

Более подробно о каждом шаге можно почитать по ссылке http://en.csharp-online.net/Creating_Custom_ASP.NET_AJAX_Client_Controls—IScriptControl.GetScriptDescriptors_Method и в MSDN.

ScriptControlTest.zip (7.95 kb)