Notas del Terrible
Заметки Ужасного Зануды

Bugs

июня 3, 2010 18:25 by terR0Q

Первое же знакомство с программой для удаленной работы с расчетным счетом привело к магическому переезду почти всей суммы на мой расчетный счет (вместо половины). При этом были перепутаны местами проставленные мной подписи: сначала подписал первый отклоненный документ, потом более новый принятый. Далее произошел непонятный мне шахер-махер подписей местами. В отклоненном поручении появился упущенный ранее пункт «НДС не облагается» и поручение было исполнено. Не критично, но мое умение выявлять баги в софте лучше все-таки не проявлять в общении с банками.


IIS: all your ASP.NET belong to us

апреля 16, 2010 18:51 by terR0Q

Парой весьма простых действий довёл IIS до того, что он перестал узнавать свою родню — ASP.NET. Любые попытки восстановить работу впустую, перерегистрация при помощи aspnet_regiis.exe -i приводила к ошибке инициализации приложения. Рецепт лечения оказался заходом с совершенно другого края: в реесте по пути HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SysPlant меняем настройку Start в значение 4, рестартим и успешно стартуем aspnet_regiis.exe -i.


Призываю чудеса

марта 19, 2010 21:36 by terR0Q

Мало того, что YouTube уже два года упорно то и дело русифицирует мой аккаунт, так теперь ещё и такое сообщение об ошибке выдал:

«Призываю чудеса.
Необходимо выбрать хотя бы один блог для добавления.»


Obsolete и XmlRoot

февраля 2, 2010 13:38 by terR0Q

Мелочь, а неприятно. Допустим, какой-то класс помечен атрибутом XmlRoot:

[XmlRoot( «SomeXmlNode» )]
public class SomeClass { ... }

Если надо пометить его, как устаревший, атрибут Obsolete надо ставить ДО XmlRoot. Иначе по факту получим еще и XmlIgnore до кучи: при операциях сохранения и чтения XML будут сыпаться ошибки о неизвестном элементе «SomeXmlNode».

Поясню. Вот такой код при сериализации выдаст исключение:

[XmlRoot( «SomeXmlNode» )]
[Obsolete]
public class SomeClass { ... }

А вот такой отработает корректно:

[Obsolete]
[XmlRoot( «SomeXmlNode» )]
public class SomeClass { ... }

Вечером посмотрю, что получается на выходе в IL при таком раскладе. Но ситуация бредовая, при том, что на уровне класса порядок атрибутов роли играть не должен. Скорее всего проблема в реализации XML-сериализатора по умолчанию. Похоже на предположение какого-то архитектора или кодера: «ну раз у нас тут устаревший узел, давайте его проигнорим».

Update.

Чуть позже нашёл в описании класса XmlSerializer заметку:

Objects marked with the Obsolete Attribute no longer serialized. In the .NET Framework 3.5 the XmlSerializer class no longer serializes objects that are marked as [Obsolete].

Т.е. в случае «ручной» сериализации получаем вообще полную лажу, когда надо было просто для кодеров сделать отметку, что класс устарел. Короче, имеем игру слов, перешедшую в возможные трудозатраты. И, к тому же, двойной баг.


Ещё одно дополнение. При установленном Language Pack SP1 работает обратное поведение: Obsolete должен быть в конце списка атрибутов, чтобы сериализация не ломалась. Как итог, для сериализуемых классов Obsolete лучше вообще не использовать. Такое ощущение, что оригинальный сериализатор делали суровые индусы и они же его потом зачем-то меняли до поставки в Language Pack.


Debug or not to debug

декабря 29, 2009 12:30 by terR0Q

Глупый вижуал студио периодически пытается убедить меня, что не может дебажить веб-приложение. Убеждает меня в этом упорно (не помогает рестарт IIS и VS), до того момент, пока я не открою web.config и не найду там debug="true".


IIS7 и проблема с загруженгными файлами WordPress

декабря 18, 2009 17:43 by terR0Q

Пока не забыл, запишу лечение назойливой проблемы с Wordpress’ом под виндой.

Симптомы

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

Причины и лечение

При проверке у загруженного файла прописаны права для IUSR (учетка, из под которой работает PHP), но не было прав для Network Service (от ее имени работает IIS). Т.е. сам веб-сервер просто не получает права доступа к файлу и выдает ошибку. Смотрится это странно, т.к. у превьюх все в порядке и при создании в этом каталоге все файлы должны наследовать права от каталога (а у него-то всё на месте).

Но в том и загвоздка, что при загрузке файлов в PHP они сначала загружаются в промежуточный каталог, указанный в php.ini (настройка upload_tmp_dir), и по умолчанию это C:\Windows\Temp, а уже потом копируется приложением PHP в целевой каталог. При этом копируются права доступа этого каталога, и они не заменяются. Потому и лечение простое: даем Network Service все нужные права на временный каталог.


BlogEngine.NET, Umbraco, IIS7 Integrated

октября 22, 2009 13:37 by terR0Q

И вновь на заметку конфигурационный рецепт, на тему как жить счастливо с BlogEngine.NET, Umbraco и интегрированным режимом работы IIS 7.

Для этого нужно, во-первых, подключить ряд обработчиков и модулей в разделе настроек веб-сервера (узел system.webServer), во-вторых, отключить модули Umbraco. Как итог прописываем следующее содержимое в конфиге BlogEngine:

   1:      <system.webServer>
   2:   
   3:          <security>
   4:              <requestFiltering allowDoubleEscaping='True'/>
   5:          </security>
   6:   
   7:          <modules runAllManagedModulesForAllRequests='true'>
   8:              <add name="WwwSubDomainModule" type="BlogEngine.Core.Web.HttpModules.WwwSubDomainModule, BlogEngine.Core"/>
   9:              <add name="UrlRewrite" type="BlogEngine.Core.Web.HttpModules.UrlRewrite, BlogEngine.Core"/>
  10:              <add name="CompressionModule" type="BlogEngine.Core.Web.HttpModules.CompressionModule, BlogEngine.Core"/>
  11:              <add name="ReferrerModule" type="BlogEngine.Core.Web.HttpModules.ReferrerModule, BlogEngine.Core"/>
  12:              <!--Remove the default ASP.NET modules we don"t need-->
  13:              <remove name="PassportAuthentication"/>
  14:              <remove name="Profile"/>
  15:              <remove name="AnonymousIdentification"/>
  16:          </modules>
  17:   
  18:          <handlers>
  19:              <add verb='*' name='File' path='file.axd' type='BlogEngine.Core.Web.HttpHandlers.FileHandler,BlogEngine.Core' />
  20:              <add verb='*' name='Image' path='image.axd' type='BlogEngine.Core.Web.HttpHandlers.ImageHandler,BlogEngine.Core' />
  21:              <add verb='*' name='Syndication' path='syndication.axd' type='BlogEngine.Core.Web.HttpHandlers.SyndicationHandler,BlogEngine.Core' />
  22:              <add verb='*' name='Sitemap' path='sitemap.axd' type='BlogEngine.Core.Web.HttpHandlers.SiteMap,BlogEngine.Core' />
  23:              <add verb='*' name='Trackback' path='trackback.axd' type='BlogEngine.Core.Web.HttpHandlers.TrackbackHandler,BlogEngine.Core' />
  24:              <add verb='*' name='Pingback' path='pingback.axd' type='BlogEngine.Core.Web.HttpHandlers.PingbackHandler,BlogEngine.Core' />
  25:              <add verb='*' name='OpenSearch' path='opensearch.axd' type='BlogEngine.Core.Web.HttpHandlers.OpenSearchHandler,BlogEngine.Core' />
  26:              <add verb='*' name='Metaweblog' path='metaweblog.axd' type='BlogEngine.Core.API.MetaWeblog.MetaWeblogHandler,BlogEngine.Core' />
  27:              <add verb='*' name='RSD' path='rsd.axd' type='BlogEngine.Core.Web.HttpHandlers.RsdHandler,BlogEngine.Core' />
  28:              <add verb='*' name='CSS' path='css.axd' type='BlogEngine.Core.Web.HttpHandlers.CssHandler,BlogEngine.Core' />
  29:              <add verb='*' name='JS' path='js.axd' type='BlogEngine.Core.Web.HttpHandlers.JavaScriptHandler,BlogEngine.Core' />
  30:              <add verb='*' name='Rating' path='rating.axd' type='BlogEngine.Core.Web.HttpHandlers.RatingHandler,BlogEngine.Core' />
  31:              <add verb='*' name='OPML' path='opml.axd' type='BlogEngine.Core.Web.HttpHandlers.OpmlHandler,BlogEngine.Core' />
  32:              <add verb='*' name='BlogML' path='blogml.axd' type='BlogEngine.Core.Web.HttpHandlers.BlogMLExportHandler,BlogEngine.Core' />
  33:              <add verb='*' name='SIOC' path='sioc.axd' type='BlogEngine.Core.Web.HttpHandlers.Sioc,BlogEngine.Core' />
  34:              <add verb='*' name='APML' path='apml.axd' type='BlogEngine.Core.Web.HttpHandlers.Apml,BlogEngine.Core' />
  35:              <add verb='*' name='FOAF' path='foaf*.axd' type='BlogEngine.Core.Web.HttpHandlers.Foaf,BlogEngine.Core' />
  36:          </handlers>
  37:   
  38:          <validation validateIntegratedModeConfiguration='false' />
  39:   
  40:      </system.webServer>

А для отключения наследования веб-настроек Umbraco «обёртываем» узлы system.web, system.web.extensions, applicationSettings и system.webServer узлом location с атрибутом inheritInChildApplications:

<location path="." inheritInChildApplications="false">   

Кстати, приём с location полезен для очень многих случаев. К сожалению, он не работает для configSections.


DotNetNuke Installation

октября 8, 2009 11:25 by terR0Q

Продолжая тему DotNetNuke, пара замечаний на счет установки.

Если система ставится на 80-й порт, то всё просто прекрасно и просто: распаковал в виртуальный каталог с запущенным приложением (просто в узел оно лезть почему-то не хочет), подключился браузером, прокликал настройки, вуа-ля! Особенно порадовало то, что в настроечном интерфейсе не забыли возможность хранения базы в локальном файле с подключением к серверу БД для его обработки. Это может быть очень удобно для разработки.

Но вот если порт какой-то ещё, и после установки сделать пару неправильных телодвижений, то скорее всего придется сбрасывать кучу внутренних настроек, а проще говоря — переустанавливать. Чтобы такого не было, надо:

  1. Подключиться к консоли localhost'а
  2. Зайти в раздел настроек системы под учетной записью host
  3. В разделе Portal Aliases добавить все те имена и адреса, по которым будут обращаться к системе с включением имени виртуального каталога (по дефолту прописано только localhost/имя_директории). Это могут быть имя_машины/dnn, имя_машины:порт/dnn, localhost:порт/dnn, ip:порт/dnn и т.п. Причем на случай переноса системы (например, с разработчетского сервера на продуктивный или тестовый) лучше заранее прописать соответствующие имена. Как вариант, можно отредактировать таблицу Port_Alias в базе.
  4. В web.config включить настройку UsePortNumber. Она там заготовлена, надо только раскомментировать.

И до кучи почти классическая ситуация, связанная с установкой модулей. Наткнулся на этот баг ещё при установке. Возможна некорректная обработка установки модуля, в результате вылетает ошибка Thread was being aborted.

Как выяснил некий Эндрю Райер (в этой теме, внизу), проблема в том, что при копировании новых dll в каталог bin, приложение перезагружается (нормальное поведение ASP.NET). Каждому потоку даётся команда на завершение. Существует таймаут, за который потоки должны завершиться, иначе они отрубаются насильно. Получается, что установщик просто не успевал отработать и его гасили. Чтобы ситуацию исправить надо немного скорректировать узел httpRuntime:

<httpRuntime useFullyQualifiedRedirectUrl="true" maxRequestLength="8192" requestLengthDiskThreshold="8192" executionTimeout="6000" shutdownTimeout="300"/>

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


UMI.CMS .NET

октября 5, 2009 03:04 by terR0Q

Дублирую пост, опубликованный ранее в ЖЖ по причине его необходимости.

Опробовал бета-версию UMI.CMS .NET. Резюмируя: даже обновлённая бета не ушла дальше сырой альфы. Далее по порядку.

Сразу скажу, что сначала использовалась версия от 22 июня этого года, в процессе шаманств с установкой получил версию от 17 августа.

Установка

Одно сделано хорошо: установка. Но и то лишь в плане простоты настройки, а время не лучшее. Суммарно ушло 20 минут, из них 10 — установка Web Platform Installer и проверка необходимых компонент. При этом не создавалась отдельная учётная запись в СУБД. Количество шагов очень небольшое. Хотя при более активных телодвижениях тот же Blogengine.NET ставится быстрее.

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

Впечатления

Памятуя презентацию на TechDays.ru хочу сказать, что все показанное там верно. Также Наружная страница веб-сайта работает гладко (а это редактирование страниц, как минимум), панель администрирования наверху также в порядке. Но! Совсем другая история с основной админкой.

Простой пример. Захожу в главный раздел, выбираю редактирование страницы «Оплата заказа», попадаю в раздел редактирования, все поля пустые. Ввожу текст в большое поле ввода (контент), нажимаю «Сохранить и посмотреть». Попадаю на страницу, где мало того, что нет введенного контента, так ещё и много заготовленной информации размещено (использовалась демонстрация магазина «Хомяки»). Дальше веселее. Меняю заголовок страницы, и о чудо, страница не найдена. Откат названия не помогает, хотя путь никто не трогал.

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

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

И ещё. Хорошие разработчики пишут хороший код сразу, хотя бы на 60—70%, а не когда каждая вторая функция хромает. Примеры тому есть: Microsoft, Google, Sun, Fog Creek. Оправданий низкому качеству быть не может: любой вклад в качество хотя и делает саму разработку дороже, но очень облегчает поддержку в будущем, чем даёт очень большую выгоду. В ином случае начинается дешёвая политика с целью распиливания бюджетов.