Saturday, October 26, 2013

Как откатиться к предыдущей версии nuget пакета

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

Вот небольшой снипет, автоматизирующий задачу.
Замените имя пакета и версию и вставьте его в Package Manager Console.

$packageName = Newtonsoft.Json;
$version = 4.0.5
$projects = Get-Project -all
$projectsWithPackage = new-object System.Collections.ArrayList;
ForEach ($proj in $projects) { Write-Host $project.ProjectName; $projWithPackage = Get-Package -Filter $packageName -ProjectName $proj.ProjectName; if($projWithPackage.Length -gt 0) { $projectsWithPackage.Add($proj.ProjectName) } }
ForEach ($proj in $projectsWithPackage) { Uninstall-Package $packageName -ProjectName $proj -Force}
ForEach ($proj in $projectsWithPackage) { Install-Package $packageName -Version $version -ProjectName $proj }


Так и не понял как разбить длинные команды на несколько строк. Почему-то консоль в студии не понимает многострочных команд и сивола `. Ваши советы пришлись бы кстати :)

Tuesday, August 20, 2013

Azure role restart at role configuration update

I had a little trouble understanding what happens when Azure role configuration changes. According to the blog post I red, which comes first in the google search, instances should be recycled one by update domain, but I didn't see it happen. It was totally misleading.

Apperently, recycling is not the default behavior. You can only reboot if you subscribe to RoleEnvironment.Changing event and set RoleEnvironmentChangingEventArgs Cancel property to true. If there is no event handling, role keeps running.

It looked like recycling was default, because the code, that subscribed to RoleEnvironment.Changing and cancelling the event, was included into the role code template before SDK 1.3 as per this blog post.

What is more, there were no mentions in MSDN that default behavior is role recycling.

Lesson learned: be careful with blog posts :)

Sunday, December 2, 2012

Собственный бекап в облаке или в леднике

Исследование

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

Воодушевлённый недавней конференцией TechEd и Windows Azure, полез считать сколько будет стоить разместить 150Gb моих драгоценных фоточег там. 
Получилось, что если хранить данные в одном регионе, то за 1Gb надо заплатить $0.93. $139.5 в месяц. Что-то много.

Смотрим Google Cloud Storage. Там $0.063 за Reduced  availability storage (читай архив), что уже не плохо, но при желании всё это скачать, придётся заплатить $0.12 per Gb + плата за реквесты. В итоге, хранение дёшево, но скачивание дорого, хоть и надо редко.

Ищем дальше.
Что есть у Amazon. Там есть S3 и Glacier. S3 предназначен также для частого доступа. На его базе можно сделать свой собственный Dropbox. Кажется, на его базе Dropbox и сделан :)
В S3 есть reduced redundancy storage за $0.093 и ... хмм Glacier storage за $0.01 per Gb. На этом стоит остановиться и посмотреть внимательнее.

Amazon Glacier

Действительно, первое, что бросается в глаза — это супер-низкая стоимость хранения. За 150Gb моих фоточег в год надо будет заплатить всего $18. Такая дешевизна, судя по отрывочной инфе, достигается за счёт специально организованного и произведённого хранилища, где диски крутятся медленно и отключаются от питания, если не задействованы. Эдакое сонное царство ну или вековой ледник. Во всём этом ледяном великолепии кроется одна большая засада — сложность и высокая стоимость извлечения данных.

Для того, чтобы рассчитать оптимальную (в идеале нулевую) стоимость скачивания, надо сломать мозг об их алгоритм рассчёта. Во-первых, надо заплатить за выкачиваемый объём по цене $0.120 per Gb или $18 за все 150Gb, что, в общем, не много, но это далеко не всё. Чтобы что-то скачать, надо отправить запрос на извлечение данных, который будет выполнятся от 3-х до 5 часов. Вот это извлечение может быть очень дорогим. Бесплатно в месяц можно извлечь 5% от среднемесячного объёма. Другими словами, чтобы скачать бесплатно всё, надо потратить 20 месяцев. Кхм... Ну хорошо, так и быть. Если приспичит скачать всё и сразу, придётся выложить порядка $270. Wow-wow-wow. Это главная засада. Если хочется всё скачать, то придётся запастись терпением. Скачивать всё, вероятно, придётся редко. Только в случае тотальной потери всех жёстких дисков, на которых записаны фоточки, а фоточки у меня записаны сразу на 2 диска.

Итак, представим, что мы хотим извлечь 0.5Gb данных. Запрос на их извлечение будет выполняться какое-то время, но для расчёта стоимости всегда берётся 4 часа. Вычисляем пиковую часовую нагрузку на извлечение так 0.5 / 4 = 0.125Gb per hour. Далее надо вычесть  из этого бесплатные месячные 5%, но в дневном потреблении. 150 * 0.05 = 7.5Gb per month / 30 days = 0.25Gb per day. Это число надо поделить на количество часов, в течение которых выполнялось извлечение за этот день. Будем считать, что мы отправляем пять запросов в день и длятся они 20 часов, то есть делим ещё на 20. 0.25 / 20 = 0.0125Gb или 12 мегабайт. Всё-таки этот сервис предназначен для больших компаний, а они хранят сотни терабайт.

Тем не менее, с учётом бесплатного объёма, часовая пиковая оплачиваемая нагрузка на извлечение равна 0.05Gb - 0.0125Gb = 0,0375Gb. Умножаем на стоимость извлечения гигабайта $0.01 и количество часов в месяце 720 и получаем счёт = $0.27. Если мы умудримся не вылезать за эту пиковую часовую нагрузку, то сможем скачать всё достаточно дёшево за 150Gb / 0.5Gb = 300 запросов на скачиваение. Если представить, что мы делаем 4 запроса в день, то получим 75 дней или 60 дней, если делаем 5. В итоге, чтобы всё скачать дёшево, нам потребуется 3 месяца.

Ещё немного об «особенностях».
- Если хочется скачать всё, то лучше размазывать это всё по целому количеству месяцев от начала до конца (в моём случае 3), поскольку если мы что-то долго качали один месяц и немного не уложились и скачали хотя бы что-то в другом, то заплатим как за два.
- Все незавершённые запросы на извлечение суммируются, то есть если мы шлём следующий запрос на извлечение, пока один не завершился, то рискуем нарваться на увеличенную пиковую нагрузку, поэтому отправляем следующий запрос только тогда, когда предыдущий завершился. Это и не даёт нам считать, что мы сможем отправлять 6 запросов по 4 часа в день. Запрос может исполняться долше.
- Надо не забыть заплатить $0.050 за каждую 1000 запросов на извлечение и загрузку.
- Надо заранее разбить все свои данные на архивы оптимального размера, потому что если мы загрузим все 150Gb одним архивом, у нас не получится так хитро его разбить. Придётся запрашивать все 150 и успеть скачать его за сутки. Поэтому надо ещё придумать механизм архивирования и разбивания файлов на архивы, а потом ещё и восстановления их из этих архивов. Кроме того, список этих архивов с их Id надо хранить где-то отдельно. Скажем, в спредшите Google docs :) чтобы было совсем всё в облаке.

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

Попробуем разобраться с их API в следующий раз.

UPD. У меня оказалось 150Gb фотографий вместо 30 :)
Ссылки:
Glacier Pricing http://aws.amazon.com/glacier/#pricing
Pricing FAQ http://aws.amazon.com/glacier/faqs/#How_much_data_can_I_retrieve_for_free
Pricing forum thread https://forums.aws.amazon.com/message.jspa?messageID=374065#374065

Friday, June 15, 2012

Тестирование сопряжения клиентского JavaScript кода и представления в MVC

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

<html>
    <header>
       <script type="text/javascript">
         var pageInitVars = { /* initial state and variable values */ }
       </script>
    </header>
    

Такое сопряжение я использую в своих приложениях. Передать некоторое состояние в JavaScript можно и другими способами, например, используя data-* атрибуты (http://api.jquery.com/data/) либо загружая только разметку в виде шаблонов, наполняя её данными с помощью ajax-запросов. http://knockoutjs.com/ — тоже очень классная штука.

Вы скажете: «Фу, буэ, ты мешаешь JS-код и разметку». Я отвечу, что нет, не мешаю, JS код лежит аккуратно в header. Не вижу особой разницы, где именно в разметке закодированы эти данные: в атрибутах html или вот так явно в специальном блоке. Преимущество данного подхода в том, что мы явно декларируем в одном месте, что наш клиентский код зависит от таких-то начальных значений. Эдакий Dependency Injection. Более того, можно автоматизировать тестирование того, что View (а именно View должна отвечать за создание эти блоков) наполняет объект pageInitVars значениями. Короче говоря, мы хотим защититься от Null Reference Exception в клиентском коде.

Можно создавать тест для каждого представления и перечислять в нём переменные для клиентского кода, который оно должно инициализировать, а можно  — держитесь крепче  — найти в клиентском коде, связанном с данным представлением, все обращения к pageInitVars и протестировать, что View эти значения передаёт через ViewModel. Мне кажется, что это довольно простая задача. Заниматься парсингом JavaScript кода не обязательно. Достаточно искать все вхождения pageInitVars, или другого объекта с более удачным названием, смотреть на то, что идёт после точки, например pageInitVars.nextPageUrl и проверять есть ли этот Url во ViewModel. А что вы думаете по этому поводу? Тестируете ли вы клиентский код таким образом?

Friday, May 25, 2012

История интеграции ASP.NET WebForms и MVC

В этом посте хочу рассказать об использовании ASP.NET MVC в уже работающем WebForms приложении. Прежде чем начать делать что-то подобное, надо ответить на вопрос «Зачем?».

Кончено, зачастую нами движет желание попробовать что-то новое в работе — испробовать какую-то новую блестящую технологию, которая в сто раз лучше старой. Это субъективный фактор, за который цепляются все остальные. Загоревшись подобной идеей, мы начинаем собирать факты «за» и стараемся не обращать внимание на «против». Хочу лишний раз предостеречь от необдуманных шагов и тем более от сценария «всё старое выкидываем и переписываем заново».

Объективно веб-формы имеют своё право на жизнь и обладают рядом преимуществ, например с ними очень быстро можно сделать веб-форму, но, скажем, реализация AJAX через UpdatePanel выглядит как надругательство над всем разумом. Поэтому первое, что было решено: постепенно менять все места, где используется AJAX на MVC и разрабатывать новый функционал тоже на MVC. Отлаженные веб-формы было решено не трогать, но подвергнуть рефакторингу.

Разработчики, использующие ASP.NET MVC стараются использовать лучшие практики программирования, и основная прелесть этой технологии как раз в том, что она подталкивает разработчика делать это изначально: разделять логику частей приложения, инвертировать управление, писать юнит-тесты. Всё это, конечно, можно делать и в веб-формах, однако, в  тех приложениях, что попадались мне на глаза ничего этого сделано не было, поэтому пришлось немало потрудиться, чтобы внедрить в них элементы MVC Framework: использовать роутинг, изолировать работу с сессией, контекстом, сервисами через их интерфейсы , а разрешать зависимости при помощи IoC контейнера ( в нашем случае использовался Unity).

Уже довольно много написано о том, как скрестить MVC и WebForms. Напишу о своём опыте: что же всё-таки было сделано, а главное — как.

Wednesday, March 23, 2011

Как изменить тип проекта VisualStudio для MVC3

У меня был проект asp.net web-forms, который я сконвертировал в MVC3 при помощи NuGet package Скотта Хансельмана.

Далее, чтобы вижуал-студия обросла необходимыми плюшками для удобной разработки на MVC3, надо поменять тип проекта. Сделать это можно, открыв .csproj файл в редакторе, и изменив ProjectTypeGuids следующим образом:
<ProjectTypeGuids>{E53F8FEA-EAE0-44A6-8774-FFD645390401};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>

Thursday, July 22, 2010

Кодогенератор для создания шаблона мета-модели

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

Предлагаемый метод не даёт на выходе 100% готовый к использованию код. Скорее, это помощник для генерации заготовки кода, которую далее всё равно придётся менять. Конечно, можно было бы написать плагин с UI для Visual Studio, но это заняло бы гораздо больше времени. :)

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