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

Для начала немного теории.  Исключение (exception) - ошибка или нестандартное поведение программы во время её работы. Например, попытка открыть файл, которого не существует, или вызвать метод элемента DOM-модели, которого нет.

В JavaScript существует конструкция try-catch-finaly, которая работает так же, как и в других языках программирования.  Логично предположить, что если есть try-catch, то должен быть и оператор throw. И такой оператор в JavaScript действительно есть. Рассмотрим пример (файл error-0.html):

HTML-код:

<div id="someButton">
</div>

JavaScript-код:

var button = document.getElementById("someButton");
button.click();


При выполнении такого кода мы получаем исключение (ошибку) такого вида:

Uncaught TypeError: Object #<an HTMLDivElement> has no method 'click'

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

Как всегда, есть два способа решения данной проблемы и при выборе какой использовать необходимо отталкиваться от конкретной ситуации. Так как тема этого поста обработка ошибок, то я не буду показывать пример проверки на существования метода click.

Добавляем в наш код конструкцию try-catch (файл error-1.html):

var button = document.getElementById("someButton");
try {
    button.click();
}
catch (e) {
document.write(e.name + ':' + e.message);
}

Что тут происходит:

  • находим элемент с id=”someButton”;
  • у найденного элемента пытаемся вызвать метод click();
  • так как такого метода у div’а нет, мы попадаем в тело блока catch;


В блоке catch у нас есть переменная e с типом Error, которая содержит два интересующих нас свойства:

  • name - тип ошибки;
  • message - текст сообщения об ошибке.

На самом деле свойств больше, но сейчас нас они не интересуют.

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

Теперь, когда мы научились обрабатывать исключения, можно создавать свои с помощью конструкции throw. Для начала определимся, какие стандартные типы ошибок есть в JavaScript:

  • SyntaxError - одна из наиболее распространённых ошибок, возникающая при неверном синтаксисе JavaScript’а;
  • TypeError - возникает когда интерпритарор JavaScript’а ожидает получить объект другого типа;
  • EvalError - ошибка при исполнении функции eval();
  • RangeError - возникает при обращении к несуществующему элементу массива;
  • URIError - возникает при выполнении decode/encode URL.


Кроме стандартных типов ошибок(исключений) можно создавать свои. Для того, чтобы бросить исключение (rise exception) необходимо использовать одну из следующих конструкций (пример смотрите в файле error-2.html):

  • throw "Error!";
  • throw new Error("Some Error");
  • throw {name:"Custom Error", message:"Custom error message"};

Ещё одна важная заметка. Так как в JavaScript в отличии от многих других языков используется объект Error вместо Exception, то в тексте значение слов “исключение” и “ошибка” имеют одинаковое значение.

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


Со времен 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


Рано или поздно при написании JavaScript’а возникает необходимость в том, чтобы он был автоматически запущен при загрузке страницы. Нужно это, как правило, для следующих действий: инициализация интерфейса (UI) и отложенная загрузка данных (lazy load).
Как часто бывает, для такой простой на первый взгляд задачи, есть несколько способов решения.

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

Способы решения:

1. Самый простой способ: в конце js-файла делаем вызов нужной функции.

menu.js:
// some javascript code
initiPageMenu();
// end of file

Самый простой способ имеет множество недостатков:

  • если скрипт подключается в теге <head>, у него нет доступа к DOM-модели;
  • вызов необходимой функции блокирует загрузку других скриптов;
  • необходимо учитывать, что к моменту загрузки скрипта, DOM-модель существует и все необходимые зависимости учтены (например, загружен другой скриат).
  • при просмотре файла menu.js не всегда очевидно, что будет выполнена функция initiPageMenu();
  • данный способ ничего не знает о UpdatePanel.

2. На серверной стороне в событии OnLoad или OnPreInit добавить следующий код:

ScriptManager.RegisterStartupScript(this,  this.GetType(), "initiPageMenu", “initiPageMenu();”, true);

Этот способ значительно лучше. Вызов функции initiPageMenu() будет помещен в конец тега <body>. Из недостатков отмечу следующее:

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

3. В файле menu.js добавить функцию page_load():

function page_load() {
    initiPageMenu();
}

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

Недостатки:

  • неширокая распространённость данного подхода (а недостаток ли это?);
  • не работает без использования на странице ScriptManager (а такие страницы ещё остались!).

4. Последний способ, о котором я хочу рассказать - событие document.ready() при использовании jQuery:

$(document).ready(initiPageMenu());

Недостаки тут тоже есть (куда же без них?)

  • необходимо использовать библиотеку jQuery;
  • как и первый, данный способ также ничего не знает о UpdatePanel.


Какой способ использовать - каждый должен выбрать сам. Единственное, на что необходимо обратить внимание - использование нескольких способов одновременно сильно усложняет понимание и сопровождение кода. Исключением из этого правила является пункт 2, но и его можно обойти при использовании IScriptControl и клиентских событий AjaxScriptManager.


Люди всегда делились на две категории: одни всегда "впереди планеты всей", вторые их догоняют. В мире программирования всё происходит аналогично: одни используют новое ПО начиная с ранних CTP (Community Technology Preview) версий, вторые переходят на них, в лучшем случае, уже после релиза. Так сложилось и в ноём текущем проекте: .net framework 4.0 вышел достаточно давно, но перейти на него получилось только сейчас, и то не полностью.

Несмотря на то, что, как правило, переход на новую версию .net framework не вызывает особых проблем (код с 3.5 успешно работает в среде 4.0), некоторые нюансы всё же есть. Нише привожу описание шагов и проблем, с которыми столкнулся.

1. Открываем наш solution (project) в Visual Studio 2010. Тут не должно быть никаких проблем: IDE сама предложит сконвертировать ваши проекты в новый формат. Если в solution нет никаких специфических проектов (например, проекты, которые создаются какими-то плагинами и их поддержки нет из коробки), то вскоре вы увидете отчёт об успешной конвертации.

2. В свойствах каждого проекта меняем Target Framework на .NET Framework 4 и пробуем всё это скомпилировать. Честно говоря, я не слышал ещё, что бы у кого-то были проблемы с этим шагом.

3. Двигаемся дальше и пробуем запусти Web Application. Вот здесь нас и поджидают первые сюрпризы. Я рассматриваю вариант, когда сайт живёт на полноценном IIS7, а не на том веб-сервере, который встроен в Visual Studio. И если при конвертации проекта не был выбран пункт “Автоматически перевести все проекты на .NET 4.0” (такое вполне вероятно когда сначала был произведен переход на Visual Studio 2010, а смена версии .NET Framework производилась посже), то вместо привычного вида своего сайта видна серверная ошибка:

error

Ошибка появляется из-за того, что немного поменялся формат файла web.config и он стал несовместимым с предыдущей версией. Решение простое - поменять web.config. И тут, как всегда, есть два способа: ручной и автоматический. Я для себя выбрал более простой и быстрый способ №2 и его советую всем. Способ заключается в запуске комнсольной утилиты из поставки IIS7 appcmd.exe. Синткаксис выглядит так:

%systemroot%\system32\inetsrv\APPCMD.EXE migrate config "Default Web Site/YourSiteName"

Более подробно о всех ключах можно почитать в помощи:

%systemroot%\system32\inetsrv\APPCMD.EXE /?

4. После этих манипуляций должно всё заработать. Но я пошел немного дальше и захотел использовать Url Routing, который есть в ASP.NET 4 (более подробно о нем можно почитать в блоге Scott Guthrie) и при открытии страниц получал 404-ю ошибку - страница не найдена. Немного покопавшись в MSDN я понял, что причина проблемы - application pool, а вернее его Managed Pipilene Mode. После выбора пункта “Integrated” всё заработало. Более подробно почитать можно на сайте IIS7.

Я описал лишь те проблемы, которые были у меня. Возможно, у вас они будут другие или вам повезёт и всё пройдет так, как рассказывает Microsoft - 2-3 клика и проект работает без проблем. Мне не повезло :(.


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

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

Кто-то может задать вполне законный вопрос: что здесь может быть нестандартного? Как показывает практика - всё.

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

Отдельное внимание стоит уделить выпадающим спискам (combobox) и полям для ввода текста (input type=”text”).

Это настоящий кошмар. Господа дизайнеры и разработчики, не трогайте их, пожалуйста! Это красиво. Это хорошо вписывается в задуманный дизайн. Возможно, это даже нравится некоторым пользователям. Но это невозможно использовать! Это кошмар для разработчиков и QA. Много примеров приводить не буду, но скажу немного о Google Docs. Кнопка “Share”. Сколько людей догадались сразу, что у неё разное поведение, в зависимости от области нажатия? Скрестили кнопку с выпадающим списком. Но это ещё далеко не самый плохой вариант. Часто фантазия дизайнеров заходит слишком далеко и разработчиком под прессом заказчика приходится это воплощать в жизнь, надеясь на то, что пользователи их не будут слишком часто воспринимать “не злым, тихим словом”.

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

Есть же guidelines, стандарты и прочее. Почему большинство предпочитает думать, что это не относится к ихнему проекту? Ведь не зря компания Apple ведет жесткую модерацию приложений для Iphone/Ipad на соответствие правилам по которым, должен выглядеть интерфейс. От этого страдают дизайнеры, немного разработчики, но счастливы пользователи (хочу отметить, что не являюсь владельцем устройства с I OS).

На этом всё. Комментарии приветствуются. Hollywar mode ON.

P.S. Пора фиксить UI баги в оформлении блога.