Разработчики JavaScript-фреймворка JQuery не перестают нас удивлять. После недавнего релиза JQuery 1.4.1 нам представили инструмент для unit-тестирования кода, написанного на JavaScript - QUnit

В данный момент поддерживаются такие функции как expect(), equals(), ok(), same(), log() и асинхронные тесты. Вместе с фреймворком распространяется css-файл, с помощью которого можно быстро и красиво выводить результаты тестов. Также разработчики активно используют его для тестирования самого JQuery, поэтому можно посмотреть уже готовые приверы от авторов фреймворка.

P.S. Что-то подсказывает мне что не загорами плагин для FireBug, по крайней мере, мне бы этого хотелось...


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

Я и сам придумал не один способ, как обмениваться данными между серверной и клиентской частью контрола. Но всегда догадывался, что есть более простой и "правильный" путь, особенно, когда смотрел на реализацию контролов из набора 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)


jQuery 1.4 Alfa 1

Published 12/7/2009 by e0ne in Web Development

Несколько дней назад вышла новая версия популярного JavaScript framework'а jQuery, пока только альфа, которую сами разработчики не рекомендуют использовать в production. Официальная информация на блоге http://blog.jquery.com/2009/12/04/jquery-14-alpha-1-released, а я расскажу о своих первых впечатлениях по сравнению с последней стабильной версией 1.3.2.

Для начала сравним размеры файлов:

jquery-1.3.2.js jquery-1.3.2.min.js jquery-1.4a1.js jquery-1.4a1.min.js
117 KB 55 KB 144 KB

87 KB

Видем что размер вырос, примерно, на 30 килобайт. Много это или мало - судите сами.

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


Почему-то, всегда забываю синтаксис вызова script service/method. Руки так и тянуться написать:

var result = ScriptServiceExample.AsmxService.Hello;
или
var result = ScriptServiceExample.AsmxService.Hello();

И каждый раз, после написания такого когда приходится лезть в MSDN/Google чтобы понять почему же оно не работает. После прочтения документации становится понятно "как" нужно писать вызов метода, но вопрос "почему" ответ, как правило, находится не сразу. Чтобы понять почему же всё работает именно так, достаточно посмотреть JavaScript код, который генерируется службой. Посмотреть это можно зайдя по адресу http://localhost:65456/AsmxService.asmx/js и сохранив себе js-файл следующего содержания:

Type.registerNamespace('ScriptServiceExample');
ScriptServiceExample.AsmxService=function() {
ScriptServiceExample.AsmxService.initializeBase(this);
// ...
Hello:function(succeededCallback, failedCallback, userContext) {
return this._invoke(this._get_path(), 'Hello',false,{},succeededCallback,failedCallback,userContext); }}
// ...

С WFC AJAX-enabled службами всё работает также.

 

ScriptServiceExample.rar (7.44 kb)


Всё началось с того, что на один из тестовых серверов поставили 64-х битную ОС. Особых проблем это не вызвало, за исключением того, что обна из сборок использует COM -объекты и появилась необходимость её сборки для платформы x86. Вот сдесь уже начали появляться первые подводные камни.

Первым делом я в свойствах проекта поменял свойство Platform Target (посже оказалось что это нужно сделать для всех проектов в solution):

 

 
Но после этих изменений ошибка "Can not load assembly ..." не пропала.  Следующим шагом пошел смотреть свойства solution и...
 
 
... и, с удивлением, обнаружил, что в качестве Target Platform для всех проектов стоит "Any CPU", вместо необходимого "x86". Пришлось идти в Configuration Manager и создавать ноую платформу для текущего solution.
 
 
Но и после всех этих танцев с бубном сайт не заработал. Тут я решил заглянуть в настройки IIS, попутно вспониная создателей Microsoft, .NET и их родственников: и это вы называете кроссплатформенной средой? Здесь меня тоже ждал сюрприз в качестве одного из параметров Application Pool'а, а именно - Enable 32-Bitt Applications, который, по умолчанию, чтоб его конечно же равен False.
 
 
Хорошо что хоть это помогло, иначе я уже был готов перустанавливать Windows и/или избавляться от старой библиотеки, которая использует COM(в нашем случае можно обойтись без этого).
 
P.S. Немного оффтопа. Стало интересно, как это всё сможет работать на x64 системах, который вовсю сейчас продвигаются Microsoft. Ещё интересно где обещанная мультиплатформенность .NET? IMHO, считаю что её нет она находится в зачаточном состоянии, т.к. всё ещё можно скомнилить сборку толоько под x86 или x64. Понимаю, что это делалось только для "нормального" запуска exe-файлов, но зачем же это было делать такой ценой?

PlatrormTestWeb.zip (10.01 kb)


ASP.NET + Mono + Apache

Published 9/22/2009 by e0ne in Mono | Web Development

Всё больше и больше можлно услышать о Mono. Как изестно, основное его идеей является реализация действительно кроссплатформенной среды .NET. Таким образом, чеще всего Mono испльзуют в операционной системе, отличной от MS Windows. А если не Windows, то Linux или какой-то из Unix. И всё было бы хорошо, если б не 2 момента (в данном случае я не акцентрирую внимание на степень готовности реализации Mono: аналог WinForms и замена Internet Information Services (IIS).На за мену WinForms приходят GTK, QTи другие библиотеки. А вот с заменой IIS все не тах хорошо: либо Apache с соответствующими модуляли, либо "родной" для Mono веб-сервер XSP2. А так как Apache наиболее популярен, то будем пользоваться им.

Все примеры я буду приводить для Ubuntu linux, но для других nix-подобных ОС все будет делаться таким же способом, за исключением установки пакетов.

Для начала нам все же надо установить Mono и IDE для нее. В качестве IDE  будем использовать MonoDevelop. Устанавливаем всё необходимое:

apt-get install mono-2.0-runtime mono-2.0-gac mono-2.0-service mono-2.0-devel mono-xsp2 mono-xsp2-base 

После чего можно запустить MonoDevelop, созать простое ASP.NET приложение и запустить. В результате получаем что-то похожее на это:

Теперь мы уже можем без проблем заниматься разработкой вплоть до момента, когда нужно запустить приложение на test-сервере, на которов, в качестве web-сервера, должен стоять Apache. Дело за малым - установить Apache и настроить его для работы с Mono.

Для наала, устанавливаем необходимы пакеты:

sudo apt-get install apache2 mono-apache-server2 libapache2-mod-mono

 

Говорим веб-серверу о необходимости загрузки нового модуля:

sudo a2enmod mod_mono

И создаём новый конфиг (/etc/mono-server2/monotest.webapp) для нашего приложения:

  <apps>
      <web-application>
         <name>Mono test</name>
         <vpath>/mono</vpath>
         <path>/var/www/</path>
        <vhost>localhost</vhost>
      </web-application>
</apps>


Последние что нас осталось сделать - это подправить конфигурационный файл Apache'а для нашего сайта (/etc/mono-server2/mono-server2-hosts.conf). Добавляем в него такие строки:

Alias /mono "/var/www"
AddMonoApplications default "/mono:/var/www"
    <Directory /var/www>
       SetHandler mono
          <IfModule mod_dir.c>
             DirectoryIndex Default.aspx
          </IfModule>
    </Directory>

Перезагружаем Apache командой:

sudo /etc/init.d/apache2 restart

И смотрим в браузере что у нас получилось:



Вчера в Киеве прошла конференция Patterns & Practices Roadshow. Изначально она должна была пройти в офисе Microsoft Ukraine, но, т.к. было многожелающих, провели её в Киевском кукольном театре. Очень красивое место и здание. Из названия было понятно, что будет обсуждаться Enterprice Library (EntLib), Entity Framework и всем, что связано с P'n'P. Догадки подтвердил опубликованный список ресурсов. 

Началось всё со вступительного слова представителя компании Microsoft Ukraine. Хотя, на самом деле всё началось с регистрации, где нам вдали пакеты с анкетой, ручкой и каким-то учебником для ВУЗов на украинском языке и кофе.


Первый доклад имел гордое название "Patterns & practices – взгляд в будущее", автором которого был Ajoy Krishnamoorthy, ведущий специалист группы patterns & practices в Microsoft, а в прошлом - PM продукта Visual Studio Team System. Было небольшое введение на тему "что такое Patterns & Practices, EntLib".

 

Вторым на сцену вышел Don Smith, которого встретили бурными авациями в том числе и из-за его Mac Book Pro, на котором оказалась установленная Windows 7.


Тут доклады немного пеменялись местами и мы услышали  доклад "Руководство по архитектуре приложений: карта вашего путешествия", который должен был быть после обеда. Но хуже от этого не стало. Нам рассказали о "Application Architecture Guide", котором написано, что он создан для разработки решений на платформе .NET, но, по сути, может быть использован при использовании и других технологий. Это же нам подтвердил Дон. Application Architecture Guide рассазывает нам о высокоарзхитектурных решениях, не вдаваясь в подробности реализации конкретных частей приложений. Думаю, что это будет интересно не только архитекторам, но и всем разработчикам. Поэтому рекомендую прочесть этот почти 400-страничный мануал.

Следующим был доклад нашего земляка Григория Мельника (Grigori Melnik).

Началось с приветствия и фразы "решил не выпендриваться и говорить на русском" (дословно). Было интересно послушать про EntLib 5,в которой будет поддерживаться совместимость до 2-й версии. Таким образом, если вы испульзовалм более старую версию библиотеки, то вы практически без проблем перейдёте на EntLib 5. К сожалению, из-за большого количества вопросов, доклад получился не полным. Григорий успел рассказать в общих чертах об Enterprice Library и рассказал о таких её частях, как Logging и Unity. Очень хотелось послушать ещё о Exception Handling и Data Access, который не является очередной ORM. Эту тему немного затронули в другом докладе, посвященному доступу к данным.

Обед. После обеда снова появился Don Smith и с докладом "Современные методы доступа к данным: шаблоны и реализации". Опять был сделан упор не на конкретную реализицию, а на то, какие вообще могут быть DataLayer. Немного была затронута тема Entity Libraкy и  LINQ to SQL. Несколько примеров приложений с разными архитектурами data layer хорошо продемонстрировали то, что Дон рассказывал и показывал на слайдах. 

Подводя итог, хочу сказать что конференция понравилась, не жалко потраченных времени/денег. Докладчики хорошо разбираются в сути вопроса и, что немаловажно, не просто говорят какие их технологии классные и нужно использовать их, а просто говорят какие есть плюсы, а иногда и минусы, тех  или иных подходов. Не было сказано не одной фразы похожей на "это классно, используйте наши технологии". Всё было достаточно объективно. Что касается организации, то не было привычных всем футболок, зато в обмен назаполенную анкету давали флешку с материалами конференции, на которой, к слову, не оказалось показанных презентаций и примеров проггрмамм, которые использовали докладчики. Так же не было EntLib 5, которая ещё не вышла в RTM.

P.S. Mike Chaliy, спасибо за фото.


Те, кто знает на память книгу Дж.Рихтера C# via .NET, в этом врядли найдут для себя что-то новое/интересное.
 

 Всё началось с того, что было у меня два похожих enum'ов (к примеру Numbers и BigNumbers) и нужно было как-то переменные первого типа приводить к другом, и наоборот. 

enum Numbers
    {
        One,
        Two,
        Three
    }

    enum BigNumbers
    {
        One,
        Two,
        Three,
        Four,
        Five
    }
На практике такие преобразования выглядят примерно так :
Numbers n1 = Numbers.One;
Numbers n2 = (Numbers) 2;
Int32 i1 = (Int32) n1;

BigNumbers b1 = BigNumbers.Five;

Numbers n3 = (Numbers) b1;

Console.WriteLine(String.Format("n1 = {0}", n1));
Console.WriteLine(String.Format("n2 = {0}", n2));
Console.WriteLine(String.Format("i1 = {0}", i1));
Console.WriteLine(String.Format("b1 = {0}", b1));
Console.WriteLine(String.Format("n3 = {0}", n3));
 

В результате на экране мы получим следующее:

n1 = One
n2 = Three
i1 = 0
b1 = Five
n3 = 4 

  Здесь мы видем, что n3 теперь равняется 4-м. Логичный, но не совсем ожидаемый для меня результат. В таком случае хотелось бы получить какой-то Exception.

 Теперь разберёмся что представляет собой enum и почему он так работает.

Enum (перечесляемый тим, enumerated type) предоставляет нам возможность хранить пару имя-значение и пришли в дополнение к константом (например: вместо того, чтоб в методе возвращать код ошибки, можно создать enum с именами ошибок).  По сути, System.Enum представляет обёкт размерного (value) типа, пронаследованного от System.ValueType:
 public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible

И, по умолчию, запись  "enum Numbers" соответствует "enum Numbers : int". В этом можно убедится, посмотрев на наше приложение с помощью IL DASM, который входит в комплект поставки .NET Framework SDK.
.class private auto ansi sealed Enums.Numbers       extends [mscorlib]System.Enum{} // end of class Enums.Numbers
.field public static literal valuetype Enums.Numbers One = int32(0x00000000)

 
Таким образом мы видем, что все элементы нашего enum являются целыми числами (int). Вместо int, можно указать byte, sbyte, short, ushort, int, long, и ulong. Интересно что если указать имя типа так, как они именуются в FCL (Byte, Int32 и т.д.), то мы получим ошибку: 
 Type byte, sbyte, short, ushort, int, uint, long, or ulong expected
 
 
Вернёмся к нашему примеру. Чтоб в нём всё работало так, как ожидалось, достаточно добавить такой код:
 if (!Enum.IsDefined(typeof(Numbers), b1)){throw new ArgumentException();}

 

Enums.zip (3.01 kb)


Решая на первый взгляд простую задачу я столкнулся с некоторыми поблемами. Задача состоит в том, чтобы из массива удалить один из его элементов. Оказалось, что стандартными средствами JavaScript этого не сделать.

Итак, у нас есть исходный массив:

var arr = new Array();
arr.push('q');
arr.push('w');
arr.push('a');
arr.push('e');
arr.push('r');
arr.push('t');
arr.push('z');
arr.push('y'); 

 Задача состоит в том, чтобы удалить из него элементы со значениями "a" и "z". Первой же идеей было использование оператора delete:

var i = arr.indexOf('a');
delete arr[i];
i = arr.indexOf('z');
delete arr[i];

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

Array.prototype.removeByValue = function(item){
        var itemIndex = -1;
        for (var index = 0; index < this.length; index++)
        {
            if (this[index] == item){
                itemIndex=index;
            }
        }
        
        if (itemIndex == -1){
            return this;
        }
        
        var resultLeft = this.slice(0, itemIndex);
        var resultRight = this.slice(itemIndex+1, this.length);
        var resultTotal = resultLeft.concat(resultRight);

        return resultTotal;

 };

 Способ использования:

var a = arr.removeByValue('a'); 
arr = a.removeByValue('z'); 

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


Всё началось с того, что в спецификации к проекту написали примерно такое: "Время продолжительности сэссии пользователя на сайте должно составлять 120 минут". После чего, в web.config была добавлена следующая строка: 

<sessionState mode="InProc" cookieless="false" timeout="120" />

А на страницу был добавлен такой мета-тег:

<meta http-equiv="Refresh" content="7200; URL=/EzRc/Pages/LogOn/SessionExpired.aspx" />

Следует упомянуть конфигурацию тестовых серверов: Windows Vista/2008, IIS7, .NET 3.5. Ничто не предвещало беды. Но, как и полагается, в один "прекрасный" день всеми людимые QA написали баг следующего содержания: "Session expiration occurs prior to 30 min (and as little as 10 min)." При этом повторить его было достаточно просто:

  • залогиниться на сайт
  • оставить браузер в покое на 30 минут

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

Ещё раз убедившись в правильности настроек сэссии в web.config я реши воспроизвести этот баг на локальном (dev) компьютере. Как ни странно, но баг воспроизводился в 100% случаев. "Странно" - подумал я и налил ещё чашку кофе.

Запустив Fiddler2 и залогинившись на сайт я снова оставил его в покое на 30 минут. Через это время, убедившись, что cookie приходят валидные, я наал смотреть логи. Напервый взгляд всё было хорошо, но присмотревшись внимательно, увидел что отрабатывает событие ApplicationStart. Теперь понятно почему заканчивается сэссия. Осталось разобраться почему перезапускается приложение.

Из логов IIS:

Event code: 1002
Event message: Application is shutting down. Reason: Hosting environment is shutting down.
Event time: 6/8/2009 1:50:21 PM
Event time (UTC): 6/8/2009 10:50:21 AM
Event ID: 80d0faffb34547fea6299cfff8cf1c6f
Event sequence: 4
Event occurrence: 1
Event detail code: 50002
 
Application information:
    Application domain: /LM/W3SVC/1/ROOT/Web-1-128889305624881519
    Trust level: Full
    Application Virtual Path: /EzRc
    Application Path: C:\Src\Sites\Web\
    Machine name: localdev
 
Process information:
    Process ID: 6364
    Process name: w3wp.exe
    Account name: NT AUTHORITY\NETWORK SERVICE

 

 

После прочтения статьи из MSDN ASP.NET Application Life Cycle Overview ответ на интересующий вопрос не был получен, из чего был сделан вывод, что проблема находится уровне выше, а именно в IIS. Начал детально изучать настройки, которые могут повлиять на работу приложения и остановился на Application Pools. После чтения документации и нескольких неверных попыток был найден источник проблемы. Им оказался параметр Idle Time-out.

 



Оказалось, что при настройках по умолчанию, процесс, отвечающий за работу asp.net, тушится при условии, что к нему не обращаются в течении 20 минут. Это объясняло, почему проблему можно было не всегда воспроизвести на тестовом сервере.

Это же можно настроить и через файл machine.config. Подробнее описано здесь.