03 (07) 2012 msdeveloperru

67
Март 2012 №3 (07) Разработчикам про технологии Microsoft Интервью с Гайдаром Магдануровым управляющим директором Фонда посевного финансирования Microsoft Интервью с Александром Косованом основателем и генеральным директором «MacPaw» Интервью с Павлом Чебуниным руководителем пресс-службы компании ISPserver.com Иерархичные структу- ры данных и промежу- точные расчеты Целые vs GUID vs Есте- ственные и Суррогатные ключи Сообщение с таймером Создание динамического веб-сайта на ASP.NET MVC3. Перемещаемые объекты Microsoft BizTalk Server 2010 R2: Основы программирования II Создание Twitter клиента на Silverlight\WPF. Вторая часть Беспроводные сети: защита и нападение Как вернуть надежность MS Project Server? Устоит ли он против Облака? Итоги конкурса Читать нас на Twitter Читать нас на Facebook

Upload: msdeveloper-ru

Post on 07-Mar-2016

260 views

Category:

Documents


26 download

DESCRIPTION

Мартовский номер журнала MSDeveloper.RU

TRANSCRIPT

Page 1: 03 (07) 2012 MSDeveloperRU

Март 2012 №3 (07)

Разработчикам про технологии Microsoft

Интервью с

Гайдаром Магдануровым

управляющим директором Фонда посевного финансирования Microsoft

Интервью с

Александром Косованом

основателем и генеральным директором «MacPaw»

Интервью с

Павлом Чебуниным

руководителем пресс-службы компании ISPserver.com

Иерархичные структу-ры данных и промежу-точные расчеты

Целые vs GUID vs Есте-ственные и Суррогатные ключи

Сообщение с таймером

Создание динамического веб-сайта на ASP.NET MVC3. Перемещаемые объекты

Microsoft BizTalk Server 2010 R2: Основы программирования II

Создание Twitter клиента на Silverlight\WPF. Вторая часть

Беспроводные сети: защита и нападение

Как вернуть надежность MS Project Server? Устоит ли он против Облака?

Итоги конкурса

Читать нас на Twitter

Читать нас на Facebook

Page 2: 03 (07) 2012 MSDeveloperRU

Рекл

ама

Page 3: 03 (07) 2012 MSDeveloperRU

Рекл

ама

Page 4: 03 (07) 2012 MSDeveloperRU

Гикам и разработчикам

Журнал выходит ежемесячно и распространяется бесплатно

Издательская группаООО «Издательство «Стангор»www.stangor.ruЖурнал MSDeveloper.RUwww.msdeveloper.ru

Издатель и руководитель проектаСтанислав Горнаков [email protected]

Зам. главного редактораИгорь Редько [email protected]

Арт-директорСветлана Петрова [email protected]

РедакторыСергей РубанИрина ВойковаАндрей КовальВасилий СенявскийМарат ЯгудинИгорь ВойковИгорь Периодов

КорректорыКсения РубоваМаксим ВеровРоман ВетринМаксим Злобин

АвторыДмитрий ПантелеичевАндрей ГордиенковНикита ЛьвовВалерий ВоробьевВладимир ИвановЕвгений КречунСергей АбаховСтанислав Горнаков

Отдел маркетинга и рекламы

Руководитель отделаВиктор Прудников [email protected]

Реклама в журнале[email protected]

Реклама на сайте журнала[email protected]

Издание зарегистрировано в Комитете Российской Федерации по ПечатиСвидетельство № ФС 77 - 3905

Журнал издает ООО «Издательство «Стангор»

Для пресс-релизов и информации о пресс-конференциях[email protected]

Авторамwww.msdeveloper.ru/about/autors.aspx

За достоверность рекламной информации ответственность несут рекламодатели. Ре-кламные материалы не редактируются и не корректируются. Редакция ждет ваших откликов и писем читателей. Фотографии, рукописи и другие печатные материалы нередактируются и не корректируются. При цитировании или перепечатывании мате-риалов ссылка на сайт www.msdeveloper.ru и название журнала MSDeveloper.RU обязательна. Полное или частичное вос-произведение материала журналов воз-можно только с письменного разрешения Издательства Стангор. Мнение редакции журнала может не совпадать с мнением авторов статей публикуемых в журнале. Все товарные знаки принадлежат их вла-дельцам.

© ООО «Издательство «Стангор»© MSDeveloper.RU

Март 2012 №3 (07)

И нтервьюИнтервью с Гайдаром Магдануровым управляющим директором Фонда посевного финансирования Microsoft

Интервью c Александром Косованом основателем и генеральным директором «MacPaw»

Интервью с Павлом Чебуниным руководителем пресс-службы компании ISPserver.com

07

28

50

А SP.NET

10Создание динамического веб-сайта на ASP.NET MVC 3. Перемещаемые объекты

B izTalk Server

Microsoft BizTalk Server 2010 R2: Основы программирования II 65

Р азработкаИерархичные структуры данных и промежуточные расчеты

Целые vs GUID vs Естественные и Суррогатные ключи

Сообщение с таймером

153252

Page 5: 03 (07) 2012 MSDeveloperRU

59

W indows PhoneЛокализовать или не локализовать: вот в чем вопрос

55

Б езопасностьБеспроводные сети: защита и нападение

S ilverlightСоздание Twitter клиента на Silverlight\WPF. Вторая часть 36

И тоги конкурсаИтоги конкурса от Microsoft

Таблица всех конкурсных приложений

2425

61

А вторская колонкаКак вернуть надежность MS Project Server? Устоит ли он против Облака?

Page 6: 03 (07) 2012 MSDeveloperRU

Рекл

ама

Page 7: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 07

И нтервью

?

?

Интервью с Гайдаром Магдануровым управляющим директором Фонда посевного финанси- рования Microsoft

Беседовал Станислав Горнаков

Наше досье

u

Пришел в компанию Microsoft в марте 2007 года на позицию эксперта по технологиям разработки программного обеспечения. До прихода в Microsoft получил образование химика-исследования и работал в Институте Элементоорганических соединений им. А.Н. Несмеянова Российской академии наук в лаборатории оптической спектроскопии в Центре спектроскопии комбинаци-онного рассеяния света. Параллельно с наукой занимался заказной разработкой, внедрением и запуском внутренних сервисов для обслуживания бизнес-процессов предприятий, а также разработкой веб-приложений. Принимал участие в разработке и запуске нескольких стартапов.

Трижды получал звание Microsoft Most Valuable Professionals в 2005, 2006 и 2007 годах.

С 2009 года руководил направлением веб-технологий в Microsoft. С 2010 года возглавил комиссию по веб-разработке при Рос-сийской ассоциации электронных коммуникаций (РАЭК).

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

Станислав Горнаков: Здрав- ствуйте, Гайдар! Спасибо, что согласились дать интер-вью журналу MSDeveloper.RU. Гайдар, вы работаете в Microsoft много лет, изначаль-но пришли на позицию еван-гелиста, а теперь занимаете должность управляющего директора фонда посевного финансирования россий-ского офиса Microsoft. Рас-скажите, пожалуйста, чем именно вы сейчас занима-етесь, за что отвечаете и какой фронт работ ведете.

Гайдар Магдануров: Работаю в Micro- soft я уже пять лет ‒ 1 марта у меня бу-дет юбилей и по этому поводу мне из штаб-квартиры пришлют стеклянную штуковину, которая будет напоминать мне об этой знаменательной дате. За прошедшие пять лет я успел позани-маться разным. Рассказывал о техно-логиях, организовывал мероприятия, работал с партнерами и заказчиками. Приходилось помогать партнерам ре-шать технические проблемы, писать и

анализировать код, разбираться в раз-ного рода хитрозакрученных архитекту-рах и предлагать пути улучшения. Было много разных увлекательных проектов в разных областях, однако всегда мне особенно нравилось помогать созда-вать, запускать и развивать новые биз-несы. И до Microsoft занимался этим как участник команд стартапов, в Micro-soft же чаще всего принимаю участие в качестве ментора для перспективных проектов, запускаю внутренние старта-пы вроде WebProfessionals.ru.

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

Уверен, что не многим на-шим читателям известна эта сторона бизнеса компании Microsoft. Компания готова

вкладывать и вкладывает деньги в стартапы. Сразу возникает вопрос, стартап должен быть обязатель-но связан с технологиями Microsoft?

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

Page 8: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 08

И нтервью

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

Есть какие-то приоритетные направления для стартапов, которые вы готовы финан-сировать или готовы рас-сматривать любые идеи?

Мы рассматриваем идеи с хорошим по-тенциалом. Важный момент, мы не ин-вестируем деньги, а предлагаем гран-ты – бесплатные деньги на создание продукта. Поэтому при отборе мы смо-трим, прежде всего, на то, что команда сможет создать успешный продукт, ко-торый может быть успешным в долго-срочной перспективе. Наши эксперты – представители инвестиционных фон-дов и государственных институтов раз- вития оценивают потенциал идеи, пред- ложенную бизнес-модель и саму ко-манду. После этого мы принимаем ре-шение исходя из простой установки – может ли наш грант помочь, учитывая размеры в 30-100 тыс. долл. США, соз-дать продукт и верим ли мы в будущую успешность продукта.

Разумеется, нам наиболее интересны продукты, укладывающиеся в стратеги-ческие направления развития – сейчас это облачные технологии – Windows Azure, это приложения для Windows Phone и следующей версии Windows. Тем не менее, нет жестких требований, мы смотрим на мир стартапов широко раскрытыми глазами.

Создать действительно хо-роший стартап в России до-статочно сложно, почему?

Отвечать на этот вопрос можно долго

и развернуто, заняв все время под ин-тервью. Позволю себе ответить тезис-но. Основная проблема – отсутствие предпринимательских знаний. Людей с нужными навыками мало, хорошее образование в этой области получить сложно, поэтому все еще не хватает технологических предпринимателей. Следующие проблемы – это сложность поиска разработчиков с нужным набо-ром навыков и привлечение «умных» денег от профессиональных инвесто-ров, готовых не просто дать деньги, но и оказать «бизнесовую» помощь.

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

Мы поддерживаем стартапы на разных уровнях. Программа BizSpark позволя-ет получить программное обеспечение для разработки и запуска продукта. Эта программа подходит для стартапов на стадии создания прототипа и разработ-ки продукта, так называемые pre-seed и seed стадии. На seed стадии помощь в создании продукта может оказать наш Фонд – за прошедший год мы уже

выдали десяти компаниям гранты на сумму более шестисот тысяч долларов США. На более поздних стадиях startup и expansion у нас есть программы мен-торской работы StartupAccelerator и BizSpark One. В первой из программ мы помогаем компаниям развивать бизнес, а во второй мы помогаем «вы-стрелить» на международной арене.

Отличная идея является ос- новой любого стартапа, на- пример, у человека или груп-пы единомышленников есть только идея, он (или они) мо-гут прийти к вам и попросить денег просто под идею?

Скажу банальность – идеи ничего не стоят. Стоимость у стартапа появля-ется когда есть целеустремленная ко-манда, готовая к созданию продукта, которую не испугает и не остановит недостаток ресурсов на реализацию идеи. Идей много, людей которые го-товы сделать достойную реализацию мало. Мы финансируем проекты уже имеющие прототипы для того, чтобы они прошли на следующий этап и сде-лали продукт. Фактически, мы ускоряем развитие компании, помогаем быстрее сделать успешный бизнес.

Хорошо, давайте теперь, что называется «на пальцах». Например, у меня есть про-ект MSDeveloper.RU, я хочу получить грант под этот про- ект от Microsoft. Что я должен сделать? Куда прийти, с кем связаться и так далее?

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

?

?

?

?

?

Page 9: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 09

И нтервью

А кто именно принимает решение о выдачи гранта?

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

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

Вы собираетесь для обсуж-дения заявок по каким-то определенным числам или все зависит от количества накопившихся заявок за какой-то промежуток вре-мени?

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

Гайдар, раскройте секрет ошибок, которые обычно делают многие стартапы на этапе именно подачи заявки и подготовки презентации. Иначе говоря, как правильно презентовать свой стартап?

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

Расскажите, пожалуйста, какие стартапы в последнее время были профинансиро-ваны Microsoft.

На самом последнем заседании мы профинансировали проект Cloud Health Care для людей больных диабетом – этот проект представляет собой портал и мобильные приложения облегчаю-щие жизнь больных и позволяющие им проще общаться с докторами. Второй проект, который мы профинансирова-ли, Alfa Smart – система распознавания психологического портрета человека по видео на интервью, которая может

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

И последний вопрос. Micro-soft - это технологическая компания и при этом она лидер данного рынка, можно даже сказать, что она и соз-дала когда-то этот рынок. Не нужно быть большим аналитиком, чтобы понять - расти этому рынку больше уже почти некуда, иначе говоря, он не может завтра взять и вырасти в двое. Где и как искать новые идеи для стартапов?

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

Гайдар, спасибо, что от-ветили на вопросы, удачи вам и побольше хороших стартапов!

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

?

?

?

?

?

?

n

Page 10: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 10

А SP.NET

АвторДмитрий Пантелеичев[email protected]Блог: http://www.msdeveloper.ru/blogs/onlinestore/Компания: TeleperformanceПрограммистг. Тверь

Создание динамического веб-сайта на ASP.NET MVC3. Перемещаемые объекты

Продолжаем совершенствование нашего сайта, создава-емого на технологии ASP.NET MVC3. Как вы помните, в январском номере мы создали два раздела: «произ-

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

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

Область моделей

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

Откроем окно Database Explorer, раскроем нашу базу данных, найдем таблицу Manufacturer, двойным щелчком откроем ее для редактирования, и добавим новое поле Sequence типа int.

Точно такое же поле добавьте в таблицу Product.

Щелкнем правой кнопкой по узлу таблицы Manufacturer, в контекстном меню выберем команду Show Table Data. От-кроется содержимое таблицы. Вручную заполним столбец Sequence целочисленными значениями в порядке возрас-тания.

Точно так же заполним столбец Sequence в таблице Product.

После того, как мы добавили новое поле в таблицы базы дан-ных, мы должны обновить классы-сущности Manufacturer и Product в объекте Entity Framework.

Откройте объект Entity Framework двойным щелчком. Если вы правильно следовали инструкциям из двух предыдущих статей, то этот объект должен находиться в папке Models, и называться EntityDataModel.edmx. Взгляните на два класса-сущности, имеющиеся в этом объекте. Ни тот, ни другой не имеют свойства Sequence.

Щелкните правой кнопкой на свободном месте окна объекта Entity Framework, и в контекстном меню выберите команду Update Model From Database. В открывшемся окне нажмите кнопку Finish. После этого взгляните снова на классы-сущ-ности Product и Manufacturer. Вы видите, что свойство Sequence появилось и у того, и у другого. u

Page 11: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 11

А SP.NET

Сохраните объект Entity Framework.

Итак, перемещаемые объекты будут отличаться от непере-мещаемых наличием свойства Sequence. Отсюда логично заключить, что нам понадобится интерфейс, который будет реализовывать все перемещаемые объекты. Создадим этот интерфейс в папке Models, подпапке Interface. Этот интер-фейс производный от интерфейса IBase, и будет дополнять его свойством Sequence. Файл назовем IOrdered.cs.

IOrdered.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;

namespace dommebeli.Models.Interface{ public interface IOrdered : IBase { int? Sequence { get; set; } }}

До сих пор наши классы-модели Manufacturer и Product реализовывали интерфейс IBase. Однако поскольку они стали теперь перемещаемыми, они должны реализовы-вать интерфейс IOrdered. Внесем изменения в код файлов Manufacturer.cs и Product.cs в папке Models.

Manufacturer.cs

using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using System.ComponentModel.DataAnnotations;using dommebeli.Models.Metadata;using dommebeli.Models.Interface;

namespace dommebeli.Models{ [MetadataType(typeof(ManufacturerMetadata))] public partial class Manufacturer : IOrdered { public bool CanBeDeleted() { if (Products.Count > 0) return false; return true; } }}

Product.csusing System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using System.ComponentModel.DataAnnotations;using dommebeli.Models.Metadata;using dommebeli.Models.Interface;

namespace dommebeli.Models{ [MetadataType(typeof(ProductMetadata))] public partial class Product : IOrdered { public bool CanBeDeleted() { return true; } }}

Область сервиса

Теперь перейдем к практическому применению этого свой-

ства Sequence. Оно нам необходимо для того, чтобы менять его значения, перемещая таким образом объекты. Сам функ-ционал будет выглядеть так.

Чтобы передвинуть объект вверх:

1. выясняем значение Sequence следующего объекта;

2. присваиваем перемещаемому объекту значение Sequence следующего объекта;

3. присваиваем следующему объекту значение Sequence перемещаемого объекта.

Чтобы передвинуть объект вниз:

1. выясняем значение Sequence предыдущего объекта;

2. присваиваем перемещаемому объекту значение Sequence предыдущего объекта;

3. присваиваем предыдущему объекту значение Sequence перемещаемого объекта.

Итак, нам понадобятся методы выяснения Sequence преды-дущего и следующего объекта. Назовем их GetPrevious и GetNext, и разместим в классах слоя сервиса.

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

Поэтому сначала создадим интерфейс слоя сервиса, ра-ботающий с перемещаемыми объектами. Создадим файл IOrderedService.cs в папке Service, подпапке Interface.

IOrderedService.csusing System;using System.Collections.Generic;using System.Linq;using System.Text;using dommebeli.Models.Interface;

namespace dommebeli.Service.Interface{ public interface IOrderedService<T>:IBaseServi- ce<T> where T:class,IOrdered,new() { // Получение ближайшего объекта с меньшим Sequence T GetPrevious(T dataObject);

// Получение ближайшего объекта с большим Sequence T GetNext(T dataObject); }}

Теперь создадим абстрактный класс, от которого будут по-рождаться все классы слоя сервиса, работающие с пере-мещаемыми объектами. В этом классе, помимо реализации методов GetPrevious и GetNext, мы должны еще переопре-делить метод Get, так как теперь этот метод должен возвра-щать объекты, отсортированные по свойству Sequence в по-рядке убывания. Создадим файл OrderedEntityService.cs в папке Service, подпапке Abstract.

OrderedEntityService.csusing System;using System.Collections.Generic;using System.Linq;using System.Web;using dommebeli.Service.Interface;using dommebeli.Models.Interface;

namespace dommebeli.Service.Abstract{ public abstract class OrderedEntityService<T> : BaseEntityService<T>, IOrderedService<T> whe- re T : class,IOrdered, new() u

Page 12: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 12

А SP.NET

{ // В списке объекты должны располагаться в порядке уменьшения Sequence public override IQueryable<T> Get() { return base.Get().OrderByDescending(item => item.Sequence); }

// Получение ближайшего объекта с меньшим Sequence public virtual T GetPrevious(T dataObject) { return (from obj in EntitySet where obj. Sequence < dataObject.Sequence order- by obj.Sequence descending select obj). FirstOrDefault(); }

// Получение ближайшего объекта с большим Sequence public virtual T GetNext(T dataObject) { return (from obj in EntitySet where obj. Sequence > dataObject.Sequence orderby obj.Sequence ascending select obj).First- OrDefault(); } }}

Внесем изменения в классы ManufacturerEntityService и ProductEntityService. Теперь эти классы должны порож-даться от абстрактного класса OrderedEntityService, по-скольку они теперь имеют дело с перемещаемыми объекта-ми.

ManufacturerEntityService.csusing System;using System.Collections.Generic;using System.Linq;using System.Web;using dommebeli.Service.Abstract;using dommebeli.Models;

namespace dommebeli.Service{ public class ManufacturerEntityService : Ordered- EntityService<Manufacturer> { dommebeliEntities entities = new dommebeli- Entities();

protected override System.Data.Objects.Object- Set<Manufacturer> EntitySet { get { return entities.Manufacturers; } } }}

ProductEntityService.csusing System;using System.Collections.Generic;using System.Linq;using System.Web;using dommebeli.Service.Abstract;using dommebeli.Models;

namespace dommebeli.Service{ public class ProductEntityService : OrderedEnti- tyService<Product> { dommebeliEntities entities = new dommebeli- Entities();

protected override System.Data.Objects.Object- Set<Product> EntitySet { get { return entities.Products; }

} }}

Внесем также изменения в фабричные классы слоя серви-са. Они теперь должны возвращать объекты типа IOrdered-Service.

ManufacturerServiceFactory.csusing System;using System.Collections.Generic;using System.Linq;using System.Web;using dommebeli.Models;using dommebeli.Service.Interface;

namespace dommebeli.Service.Factory{ public static class ManufacturerServiceFactory { public static IOrderedService<Manufactu- rer> Create() { return new ManufacturerEntityService(); } }}

ProductServiceFactory.csusing System;using System.Collections.Generic;using System.Linq;using System.Web;using dommebeli.Models;using dommebeli.Service.Interface;

namespace dommebeli.Service.Factory{ public static class ProductServiceFactory { public static IOrderedService<Product> Create() { return new ProductEntityService(); } }}

Область контроллеров

Переходим теперь к контроллерам. Контроллеры, работаю-щие с перемещаемыми объектами, должны иметь действия, перемещающие объект вверх или вниз. Назовем их Up и Down.

Создадим абстрактный класс OrderedController, от которо-го будут порождаться все контроллеры, работающие с пере-мещаемыми объектами. Этот класс порождается от абстракт-ного класса BaseController, и дополняет его действиями Up и Down. Эти действия будут доступны только администратору или контент-менеджеру, поэтому к ним должен быть добав-лен соответствующий фильтр. Папка Controllers, подпапка Abstract, файл OrderedController.cs.

OrderedController.csusing System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using dommebeli.Models.Interface;using dommebeli.Service.Interface;

namespace dommebeli.Controllers.Abstract{ public abstract class OrderedController<T> : Ba- seController<T> where T : class,IOrdered, new() { public OrderedController(IOrderedServi- u

Page 13: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 13

А SP.NET

ce<T> _service) : base(_service) { }

#region Actions

// Перемещение объекта вверх [Authorize(Roles = Constants.ROLES_ADMIN_CON- TENT_MANAGER)] public ActionResult Up(int id) { T obj = service.Get(id);

if (obj == null) return View(“NotFound”); else { if (obj.Sequence.HasValue) { T next = (service as IOrderedSer- vice<T>).GetNext(obj);

if (next != null) { int? curSeq = obj.Sequence; int? nextSeq = next.Sequence;

obj.Sequence = nextSeq; next.Sequence = curSeq; service.Save(); } }

return OnUp(obj); } }

// Перемещение объекта вниз [Authorize(Roles = Constants.ROLES_ADMIN_CON- TENT_MANAGER)] public ActionResult Down(int id) { T obj = service.Get(id);

if (obj == null) return View(“NotFound”); else { if (obj.Sequence.HasValue) { T previous = (service as IOrdered- Service<T>).GetPrevious(obj);

if (previous != null) { int? curSeq = obj.Sequence; int? prevSeq = previous.Sequence;

obj.Sequence = prevSeq; previous.Sequence = curSeq; service.Save(); } }

return OnDown(obj); } }

#endregion

#region Virtual methods

// Перенаправление после перемещения объекта вверх protected virtual ActionResult OnUp(T obj) { return ReturnToList(obj); }

// Перенаправление после перемещения объекта вниз protected virtual ActionResult OnDown(T obj) { return ReturnToList(obj); }

#endregion

#region Overridden virtual methods

// При создании объекта автоматически задаем ему значение Sequence, равное следующему после наибольшего protected override void AddValuesOnCreate(T obj) { base.AddValuesOnCreate(obj); obj.Sequence = GetNextSequence(servi- ce.Get().Select(item => item.Sequence)); }

#endregion

#region Methods

// Получаем значение Sequence, следующее после наибольшего protected virtual int GetNextSequence(IQuery- able<int?> seqs) { if (seqs.Count() == 0) return 1; else { int? iMax = seqs.Max(); if (iMax.HasValue) return iMax.Value + 1; else return 1; } }

#endregion }}

Вносим изменения в классы ManufacturerController и ProductController. Они теперь должны порождаться от аб-страктного класса OrderedController и связываться с базой данных через объекты типа IOrderedService.

ManufacturerController.csusing System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using dommebeli.Models;using dommebeli.Service.Interface;using dommebeli.Service.Factory;using dommebeli.Controllers.Abstract;

namespace dommebeli.Controllers{ public class ManufacturerController : OrderedCon- troller<Manufacturer> { public ManufacturerController(IOrderedServi- ce<Manufacturer> _service) : base(_service) { }

public ManufacturerController() : this(ManufacturerServiceFactory.Create()) { } }}

ProductController.csusing System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using dommebeli.Models;using dommebeli.Service.Interface;using dommebeli.Service.Factory;using dommebeli.Controllers.Abstract;

namespace dommebeli.Controllers{ public class ProductController : OrderedControl- ler<Product> { u

Page 14: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 14

А SP.NET

public ProductController(IOrderedService<Pro- duct> _service) : base(_service) { }

public ProductController() : this(ProductSer- viceFactory.Create()) { }

protected override void ChangeFormCollection- Values(Product obj, FormCollection collection) { base.ChangeFormCollectionValues(obj, col- lection);

collection[“Price”] = collection[“Price”]. Replace(“ “, “”);

collection[“Price”] = collection[“Price”].Re- place(“,”, System.Globalization.CultureIn- fo.CurrentCulture.NumberFormat.CurrencyDeci- malSeparator);

collection[“Price”] = collection[“Price”].Re- place(“.”, System.Globalization.CultureIn- fo.CurrentCulture.NumberFormat.CurrencyDeci- malSeparator); } }}

Область представления

Все, что осталось, это добавить ссылки «Вверх» и «Вниз» на странице списка объектов. Так как перемещать объекты могут только администраторы или контент-менеджеры, мы должны дополнить ссылки проверкой на авторизацию и об-ладание нужными ролями. Список объектов формируется в файлах представления Index.cshtml разделов Manufacturer и Product. Вносим туда соответствующие изменения.

Views – Manufacturer – Index.cshtml@model IEnumerable<dommebeli.Models.Manufacturer>

@{ ViewBag.Title = string.Format(“Производите- ли | {0}”, dommebeli.Constants.TITLE);}

<h2>Производители</h2>

@if (Request.IsAuthenticated && (User.IsInRo-le(dommebeli.Constants.ROLE_ADMIN) || User.IsIn-Role(dommebeli.Constants.ROLE_CONTENT_MANAGER))){ <p>@Html.ActionLink(“Создать”, “Create”)</p>}

<table>@foreach (var item in Model){ <tr> <td>@Html.ActionLink(item.Name, “Details”, new { id = item.ID })</td> @if (Request.IsAuthenticated && (User.IsInRole(dommebeli.Constants.RO- LE_ADMIN)

|| User.IsInRole(dommebeli.Constants.RO- LE_CONTENT_MANAGER))) { <td style=”padding-left:30px;”>@Html.Acti- onLink(“Вверх”, “Up”, new { id = item.ID })</td>

<td style=”padding-left:30px;”>@Html.Acti- onLink(“Вниз”, “Down”, new { id = item.ID })</td> } </tr>}</table>

Views – Product – Index.cshtml@model IEnumerable<dommebeli.Models.Product>

@{ ViewBag.Title = string.Format(“Товары | {0}”, dom- mebeli.Constants.TITLE);}

<h2>Товары</h2>

@if (Request.IsAuthenticated && (User.IsInRo-le(dommebeli.Constants.ROLE_ADMIN) || User.IsInRo-le(dommebeli.Constants.ROLE_CONTENT_MANAGER)))

{ <p>@Html.ActionLink(“Создать”, “Create”)</p>}

<table>@foreach (var item in Model){ <tr> <td>@Html.ActionLink(item.Name, “Details”, new { id = item.ID })</td>

@if (Request.IsAuthenticated

&& (User.IsInRole(dommebeli.Constants.RO- LE_ADMIN)

|| User.IsInRole(dommebeli.Constants.RO- LE_CONTENT_MANAGER))) { <td style=”padding-left:30px;”>@Html.Acti- onLink(“Вверх”, “Up”, new { id = item.ID })</td>

<td style=”padding-left:30px;”>@Html.Acti- onLink(“Вниз”, “Down”, new { id = item.ID })</td> } </tr>}</table>

Зайдите на сайт под учетной записью администратора, от-кройте список товаров или список производителей. Рядом со ссылкой на страницу объекта должны появиться ссылки «Вверх» и «Вниз». Попробуйте переместить объекты. Убеди-тесь, что функция работает. Попробуйте создать новый объ-ект. Он должен встать в начало списка.

Заключение

Итак, мы рассмотрели способ, как можно сделать объекты перемещаемыми. Мы добавили новые возможности, не вно-ся изменений в уже существующую функциональность. Так, например, мы оставили нетронутыми абстрактные классы, созданные ранее, и содержавшие базовые возможности работы с объектами: BaseController, BaseEntityService. Для добавления новых возможностей мы создали новые аб-страктные классы, породив их от старых. И таким образом эти классы унаследовали все прежние возможности, добавив новые.

Этот пример демонстрирует, насколько хорошо платформа ASP.NET MVC сочетается с объектно-ориентированным про-граммированием, и насколько широко позволяет пользовать-ся его приемами. n

Page 15: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 15

Р азработка

Иерархичные структуры данных и промежуточные расчеты

АвторАндрей Гордиенков[email protected]://softblog.violet-tape.ru/г. Москва

Традиционной, в плане изучения программирования в школах, университетах, курсах повышения квалификации и так далее – является архитектура, в которой мы явно

управляем ходом выполнения программы. Это начинается с фактически процедурного турбо-паскаля и идеологически продолжается в «рабочих» для бизнес-программирования языках (С# и Java). Каждое действие программы задается явно, т.е. если надо что-то пересчитать после добавления нового элемента в коллекцию, то так и пишут: сервис Х, пере-считай мне коллекцию с помощью метода Z. Это – push мо-дель, мы толкаем/принуждаем систему сделать определен-ные действия.

Более интересной является pull модель, когда объекты сами говорят о том, что они готовы для работы. При той же ситуа-ции, что описана выше, надо только добавить объект в кол-лекцию, а дальше уже коллекция сама может сказать сервису Х пересчитать себя с помощью метода Z. Система реагирует на события внутри себя.

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

Немного о Rx

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

Данная библиотека разработана в недрах MS Lab и активно продвигается как для десктоп платформ, так и для WP7. Луч-ше всего устанавливать библиотеки для работы с помощью менеджера компонентов NuGet.

Сам Rx Framework является набором методов расширений для базовых интерфейсов

IObservable<T>IObserver<T>

Базовым элементом Rx является класс Subject<T> реализу-ющий оба интерфейса. Управление потоком событий проис-ходит с помощью трех методов:

{ OnNext – выдать новое значение в поток;

{ OnComplete – указать на завершение потока;

{ OnError – указать на ошибку при выполнении;

Все оказывается логично и пока что не очень сложно.

Самое главное, что нужно для себя понять ‒ это то, что работа с Rx подразумевает работу именно с потоком данных/событий. Это не коллекция объектов, не какой-либо статичный набор, это именно поток данных, который идет на обработку с некоторой скоростью.

Если хочется самостоятельно покопаться с Rx то хорошо на-чать с цикла статей у Ли Кэмпбела.

Вводные данные

Работать будем со структурой, которую наверно каждый в своей жизни хоть раз да написал. Иерархия классов с указа-нием на родителя и коллекцию дочерних элементов того же типа. При этом всегда надо было осуществлять какие-либо суммарные подсчеты. У всех такое было, да?

В таком случае классическая структура класса не требует до-полнительных пояснений.

public class CategoryClassic { private readonly List<CategoryClassic> items = new List<CategoryClassic>();

public CategoryClassic Parent { get; private set; } public string Name { get; set; }

public ReadOnlyCollection<CategoryClassic> Items { get { return items.AsReadOnly(); } }

public int DebtCount { get; set; } public int CreditCount { get; set; } public decimal DebtSummary { get; set; } public decimal CreditSummary { get; set; }

public void Add(CategoryClassic category) { if (items.Contains(category)) return; items.Add(category); category.Parent = this; }

public void Remove(CategoryClassic category) { category.Parent = null; items.Remove(category); }

public int CountAllDescendants() { var count = items.Count; items.ForEach(i => count = count + i.Count- AllDescendants()); u

Page 16: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 16

Р азработка

return count; }}

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

От этого классического примера будем отталкиваться.

Задача

Надо посчитать суммы по DebtCount и другим полям для каж-дого уровня. Оценить затраты при единовременном состав-лении дерева, а так же при добавлении элементов в дерево.

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

Реализация в моем случае в виде сервиса, так как именно это я вытащил из недр текущего проекта на работе.

public class CategoryClassicCalcService { public void Calculate(CategoryClassic category) { if(category.Items.Count == 0) return;

category.Items.ToList().ForEach(Calculate);

category.CreditCount = category.Items.Sum(i => i.CreditCount);

category.CreditSummary = category.Items.Sum(i => i.CreditSummary);

category.DebtCount = category.Items.Sum(i => i.DebtCount);

category.DebtSummary = category.Items.Sum(i => i.DebtSummary); }}

Простые тесты приводить не буду, рассмотрим те, где появ-ляются упомянутые ранее NBuilder и FluentAssertions.

Лирическое отступление о NBuilder

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

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

{ Метод для добавления нового элемента в иерархию,{ Глубину иерархии,{ Минимальное количество потомков на узел,{ Максимальное количество потомков на узел,{ Метод именования, если надо,{ Количество корневых узлов.

Данный класс описывает правила, по которым надо будет строить иерархию. Для построения самой иерархии восполь-зуемся методом BuildHierarchy.

[Test]public void ShouldSummarizeByHierarchy3Level() { // Arrange var hierarchySpec = new HierarchySpec<Catego-

ryClassic> { AddMethod = (parent, child) => parent.Add(child), Depth = 3, MinimumChildren = 1, MaximumChildren = 1, NamingMethod = (item, index) => item.Name = “Category “ + index, NumberOfRoots = 1 }; var root = Builder<CategoryClassic>.CreateListOf- Size(5) .BuildHierarchy(hierarchySpec).First(); var service = new CategoryClassicCalcService();

root.CreditCount.Should().Be(1);

// Act service.Calculate(root);

// Assert root.CreditCount.Should().Be(0 + 0 + 0 + 4);}

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

По самому тесту особых пояснений думаю не надо делать. Создаем определение на трехуровневую иерархию по одно-му элементу на уровень. Затем строим иерархию, считаем и проверяем результат.

Результаты нагрузочного тестирования

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

Замер начинается до объявления спецификации на постро-ение иерархии и останавливается сразу после пересчета по-лей.

Элементов: 55 986 Время построения (ms): 8 552 Время добавления и пересчета (ticks): 128 909

Хорошо, просто запомним эти цифры, пока что это ни о чем не говорит. Хотя конечно пересчет длителен, но другого не ожидалось.

Построение на событиях

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

Реализация значительно разрастется, что и говорить. Начнем с того, что внутренней коллекцией будет ObservableCollec-tion, подпишемся на изменение коллекции в конструкторе. Когда это событие возникнет, надо пересчитать суммы и со-общить родителю (если он есть). Но лучше сделать заглушку для делегата, чтобы не вставлять лишнюю проверку.

public event Action SummaryChanged;public CategoryNotify() { u

Page 17: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 17

Р азработка

SummaryChanged = () => { };

items = new ObservableCollection<CategoryNotify>(); items.CollectionChanged += UpdateSummary;}

При изменении коллекции, пересчитываем суммы и рапорту-ем выше с помощью метода SummaryChanged:

private void UpdateSummary(object sender, NotifyCol-lectionChangedEventArgs e) { UpdateSummary();}private void UpdateSummary() { CreditCount = items.Sum(i => i.CreditCount); DebtCount = items.Sum(i => i.DebtCount);

CreditSummary = items.Sum(i => i.CreditSummary); DebtSummary = items.Sum(i => i.DebtSummary); Calls++; SummaryChanged();}

Так хитро сделано для удобства подписки родителей.

При добавлении нового элемента, подписываемся на его со-общения об изменении его коллекции дочерних элементов.

public void Add(CategoryNotify category) { if(items.Contains(category)) return;

items.Add(category); category.Parent = this; category.SummaryChanged += UpdateSummary;}

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

Честно сказать, в событиях можно запутаться на раз, и я не с первого раза написал события как надо, да и потом пере-читывать не просто. Зато быстро работает при обновлении! Кстати о тестах:

Элементов: 55 986 Время построения (ms): 10 007 Время добавления и пересчета (ticks): 72

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

Rx реализация

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

Итак, нужен базовый объект из Rx, который будет реализовы-вать необходимые нам интерфейсы. Я выбрал ReplayObject, так как он помнит все пришедшие значения. private readonly ReplaySubject<CategoryRx> addedSubject = new ReplaySubject<CategoryRx>();

В этом варианте обойдемся без конструктора, и без ObservableCollection.

public void Add(CategoryRx category) { if (items.Contains(category)) return;

items.Add(category); category.Parent = this; category.addedSubject .Subscribe(Update);

Update(category);}

private void Update(CategoryRx category) { CreditCount = items.Sum(i => i.CreditCount); DebtCount = items.Sum(i => i.DebtCount);

CreditSummary = items.Sum(i => i.CreditSummary); DebtSummary = items.Sum(i => i.DebtSummary); Calls++; addedSubject.OnNext(this);}

Меньше кода и компактнее. Смысл тот же. При добавлении подписываемся на событие добавления нового элемента (строка 6-7), пересчитываем собственные показатели (метод Update) и говорим родителю об обновлении (последняя стро-ка).

Метод OnNext, возбуждает событие с указанным параметром. Делегат, указанный в методе Subscribe, принимает параметр из события, которое было возбуждено методом OnNext. Про-ще ведь, а? Однако посмотрим что там со временем выпол-нения.

Элементов: 55 986 Время построения (ms): 14 125Время добавления и пересчета (ticks): 182

Думал, что будет быстрее, однако, тоже неплохой в целом ре-зультат. Большие задержки видимо объясняются внутренним устройством ReplaySubject и тем, как происходит возбуж-дение события и его обработка. Это ведь дополнительный уровень абстракции.

Итоги

Итоги для работы с 55 986 элементами представлены в та-блице ниже

Из всего этого можно сделать следующие выводы:

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

{ Если добавления ожидаются и немало, то следует для себя решить, что важнее: скорость или читабельность.

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

Касательно Rx, я думаю, что можно и тут добиться ускорения построения общей структуры, если использовать правильно метод Throttle. Однако у меня не получилось, чего-то не учел. Но я еще учусь и пробую, так что как найду способ, обя-зательно расскажу.

Про Rx пока что рассказано совсем чуть-чуть, но большин-ство методов расширения еще рассмотрим позже, плюс они оставляют впечатление некоторой синтетичности. n

Способ Время построения (ms)

Время добавления и пересчета (ticks)

Classic 8552 128909Event 10007 72Rx 14125 182

Source Code

Page 18: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 18

В izTalk Server

Microsoft BizTalk Server 2010 R2: Основы программирования II

АвторЕвгений Кречун [email protected]Сайт: www.krechun.com Компания «Астерос»MCTS: Microsoft BizTalk Server 2010г. Москва

В февральской статье мы рассмотрели основные компо-ненты для программирования под BizTalk Server (здесь и далее BTS), выбрав довольно простую задачу по сло-

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

Задача

Думаю, вы уже сталкивались с системами, которые связаны друг с другом по принципу «каждый с каждым», т.е. каждая система напрямую связана с любой другой. Минусы такой организации взаимодействия можно легко назвать навскид-ку. В первую очередь, это трудности по реализации взаимо-действия с каждой конкретной системой. Если, например, в комплексе штук 30 систем, привязываться по определенным протоколам к другим 29 системам очень и очень накладно. К тому же, если одна система изменит какой-то свой формат передачи данных, то всем остальным системам нужно будет поменять свои внутренние реализации взаимодействия.

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

Теперь перейдем к нашему проекту. Предположим, что сам BTS не умеет решать задачу «сложить числа A и B». Это, конечно, смешно и неправда, но под задачу сложения двух чисел можно подставить любую другую. На данный момент нам нужно, чтобы результаты вычислений брались из другой системы. В реальных системах под такой задачей может сто-ять получение каких-то данных, например, справочников или результатов каких-то сложных вычислений.

Определимся с участниками нашего процесса:

{ Шина,

{ Модуль User, запрашивающий информацию у шины,

{ Модуль CalcService, который умеет считать результат.

Можно нарисовать диаграмму последовательности работы по процессу.

Модуль User запрашивает информацию у шины, шина деле-гирует запрос сервису CalcService, который этой информа-цией обладает, ждет ответа от этого сервиса и возвращает затем этот ответ к модулю User. Итого нам нужно разрабо-

тать два веб-сервиса и шину. Начнем с написания заглушки к шине.

Решение

В данном разделе будет описываться создание интеграционной шины с ис-пользованием Microsoft Visual Studio 2010. Я предполагаю, что читатель оз-накомился с предыдущей февральской статьей, а также умеет создавать WCF-сервисы.

Создание заглушки шины

Откроем Visual Studio 2010 от имени администратора, создадим новый про-ект EsbSample.EsbCore, студия, как обычно, сгенерирует заготовку реше-ния и проекта.

Общий вид оркестровки

Сейчас нужно закодировать процесс, для этого в сборку EsbSample.EsbCore нужно добавить новую оркестровку CalcProcess. После добавления орке-стровки можно набросать сценарий ра-боты. Его можно прочитать следующим образом: u

Page 19: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 19

В izTalk Server

{ Receive_1 ‒ получает запрос на сложение двух чисел,

{ Send_1 ‒ отправляет запрос сервису сложения чисел,

{ Receive_2 ‒ получает результат сложения,

{ Send_2 ‒ отправляет результат сложения.

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

Схемы

Запрос

Добавим в проект схему для запроса (EsbRequest) и созда-дим следующую структуру:

Вот ее код:

<?xml version=«1.0» encoding=«utf-16»?><xs:schema xmlns=«http://EsbSample.EsbCore.EsbRequest» xmlns:b=«http://schemas.microsoft.com/Biz- Talk/2003» targetNamespace=«http://EsbSample.EsbCore.Esb- Request» xmlns:xs=«http://www.w3.org/2001/XMLSchema»> <xs:element name=«Request»> <xs:complexType> <xs:sequence> <xs:element name=«A» type=«xs:int» /> <xs:element name=«B» type=«xs:int» /> <xs:element name=«CorrelationID» type=«GUID» /> </xs:sequence> </xs:complexType> </xs:element> <xs:simpleType name=«GUID»> <xs:restriction base=«xs:string»> <xs:pattern value=«[a-fA-F0-9]{8}-[a-fA-F0-9] {4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9] {12}» /> </xs:restriction> </xs:simpleType></xs:schema>

Ответ на запрос

Аналогичным образом добавим еще одну схему EsbResponse, следующего вида:

<?xml version=«1.0» encoding=«utf-16»?><xs:schema xmlns=«http://EsbSample.EsbCore.EsbResponse» xmlns:b=«http://schemas.microsoft.com/Biz- Talk/2003» targetNamespace=«http://EsbSample.EsbCore.Esb- Response» xmlns:xs=«http://www.w3.org/2001/XMLSchema»> <xs:element name=«Response»> <xs:complexType>

<xs:sequence> <xs:element name=«Result» type=«xs:int» /> <xs:element name=«CorrelationID» type=«Guid» /> </xs:sequence> </xs:complexType> </xs:element> <xs:simpleType name=«Guid»> <xs:restriction base=«xs:string»> <xs:pattern value=«[a-fA-F0-9]{8}-[a-fA-F0-9] {4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9] {12}» /> </xs:restriction> </xs:simpleType></xs:schema>

Логические порты

Создание типов логических портов

Итак, у нас определены схемы сообщений, сейчас можно соз-давать логические порты. Для этого вначале создадим два типа портов ‒ один для запроса, второй для ответа. Созда-ние типа порта для запроса начинается в окне Orchestration View, нужно найти узел Port Types и через контекстное меню вызвать команду создания типа порта:

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

Page 20: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 20

В izTalk Server

Здесь я создал тип порта под названием RequestPortType, c одной операцией Calc и типом запроса EsbRequest.

Аналогичным образом создается тип порта для ответов:

Таким образом, у нас появилось два типа порта, теперь нам нужно создать сами порты.

Создание портов

Для Receive_1 создадим порт InboundPort со следующей конфигурацией:

Для SendPort_1 конфигурация порта будет аналогична, толь-ко на экране Port Binding нужно выбрать Port direction of communication: I’ll always be sending messages on this port.

Для Receive_2 конфигурация будет выглядеть вот так:

Для Send_2 создание порта аналогичное, только на экране Port Binding нужно указать Port direction of communication: I’ll always be sending messages on this port.

После создания портов нужно аккуратно соединить соответ-ствующие коннекторы, чтобы получилась следующая карти-на: u

Page 21: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 21

В izTalk Server

Обращаю внимание на то, что когда соединяется порт и фи-гура Receive, автоматически создается сообщение, в то вре-мя как при соединении фигур Send сообщения не создаются. Поэтому в окне Orchestration View в узле Messages нужно создать два сообщения типа EsbResponse:

Таким образом, у нас должно получиться 4 сообщения, нуж-но их переименовать и установить в каждой фигуре Receive\Send соответственно таблице:

Название Тип Название фигуры

RcvdMsg_1 EsbRequest Receive_1

RcvdMsg_2 EsbResponse Receive_2

SntMsg_1 EsbRequest Send_1

SntMsg_2 EsbResponse Send_2

Пример установки сообщения для фигуры:

Если вы все сделали верно, то получится следующая картин-ка.

Заметим, что иконка с восклицательным знаком осталась только у фигур ConstructMessage. Давайте займемся ими, выделяем ConstructMessage_1, выбираем его свойства и указываем, что мы будем создавать сообщение SntMsg_1.

После этого добавляем в приложение две карты (map), с на-званиями CopyRequest и CopyResponse. Как нетрудно дога-даться из названий карт, каждая из них будет просто копиро-вать из одного сообщения в другое, сообщения должны быть одинакового типа. Пример для CopyRequest:

После того как карты созданы, можно удалить фигуры Mes-sage Assignment, которые распола- гаются внутри фигур Construct Mes-sage и поставить туда взамен фигуры Transform.

Затем нужно два раза щелкнуть по Transform_1 (откроется окно Trans-form Configuration) и установить сле- дующие параметры:

{ Existing Map (Fully Qualified Map Name=”EsbSample.EsbCore.CopyRequest”)

{ Transform Source: RcvdMsg_1{ Transform Destination: SntMsg_1 u

Page 22: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 22

В izTalk Server

Для фигуры Transform_2 нужно совершить аналогичные действия:

{ Existing Map (Fully Qualified Map Name=”EsbSample.EsbCore.CopyResponse”)

{ Transform Source: RcvdMsg_2

{ Transform Destination: SntMsg_2

После всех этих манипуляций нужно у фигуры Receive_1 установить свойство Activate = True и оркестровка почти готова.

Корреляции

Вернемся к описанию нашего процесса. Итак, шина полу-чает запрос на вычисление, адресует это вычисление веб-сервису, а затем ждет сообщения с ответом. Допустим, вы-числение результата занимает какое-то время, скажем, минут 10. В течение этого времени к нам придет еще один запрос на вычисление, мы также делегируем его сервису, и ровно так же будем ждать ответа. Здесь возникает вопрос – когда к нам придет сообщение с ответом, ответом на какой запрос оно будет являться, на первый или на второй? Неясно. Для этого было введено понятие корреляции, т.е. соответствия сообщений. В наших схемах для корреляции выделено поле CorrelationID.

Работает это следующим образом: нам приходит первый за-прос с CorrelationID = «cfc2e57b-63fe-44c8-b071-047e1a34 b413», мы перенаправляем этот запрос веб-сервису. И затем ждем сообщения с ответом, где в поле CorrelationID будет стоять значение «cfc2e57b-63fe-44c8-b071-047e1a34b413». Соответственно, если нам придет второй запрос, то Corre-

lationID у него будет другим, и путаницы в этом случае уже не возникнет.

Для настройки корреляции нам нужно немного поправить схемы. Начнем с EsbRequest, открываем его в редакторе, вы-бираем поле CorrelationID и в контекстном меню выбира-ем команду Promote \ Quick Promotion. В проект добавится файл PropertySchema.xsd, в него добавится наше свойство. Аналогичные действия нужно совершить с EsbResponse.

Затем переходим обратно в оркестровку, в окне Orchestration View выбираем узел Correlation Types и создаем новый тип корреляции:

Находим в списке Available Properties нашу схему со свой-ствам, выбираем CorrelationID, нажимаем кнопку Add:

Получился тип корреляции, завязанный на поле Correlati-onID: u

Page 23: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 23

В izTalk Server

Затем в окне Orchestration View выбираем узел Correlation Sets, добавляем новый набор корреляции и указываем в ка-честве ее типа только что созданный:

После этого нам в оркестровке нужно где-то «запомнить», инициализировать корреляцию. Если взглянуть на оркестров-ку, можно заметить одно место, где она нам пригодится – ког-да мы ожидаем ответа от веб-сервиса по расчету данных, это фигура Receive_2, в нее мы ждем сообщения именно с тем идентификатором корреляции, который был отправлен ранее в сообщении Send_1. Поэтому выделяем фигуру Send_1 и уста-навливаем у нее свойство Initializing Correlation Sets:

А у фигуры Receive_2 устанавливаем свойство Following Correlation Sets:

Таким образом, при отправке сообщения через Send_1 мы за-поминаем CorrelationID и затем в Receive_2 ждем сообще-ния, у которого CorrelationID будет таким же. Все просто.

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

Развертывание приложения

Теперь нам нужно развернуть приложение. Для этого вна-чале нужно открыть свойства проекта, подписать сборку на вкладке Signing, а затем задать настройки развертывания на вкладке Deployment (все это было описано в прошлой ста-тье). Название у приложения будет «Esb». После этого нужно выбрать в меню Build – Deploy Solution.

Если вы все сделали правильно, в окне Output будет сказано об успешном развертывании приложения. А если нет, пишите письма, разберемся.

На данном шаге я предлагаю прерваться и продолжить в сле-дующей части.

Что дальше

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

Исходники проекта

Page 24: 03 (07) 2012 MSDeveloperRU

Журнал MSDeveloper.ru и портал AppProfessionals.ru при поддержке Microsoft подводит

итоги конкурса приложений для платформы Windows Phone 7.

Приятно заметить, что в нашем конкурсе в общей сложности приняло участие

104 приложения ‒ это абсолютный рекорд среди подобных конкурсов!

Лучшее приложение

1 1 1

2

3

2

3

2

3

Ape the Wall (XIMAD Inc.)

приз смартфон HTC Mozart

Undead Carnage (Михаил Галушко)

рекламный модуль в журнале MSDeveloper.RU и банер на сайте журнала

Курсы валют (Жилинков Вадим)

рекламный модуль в журнале MSDeveloper.RU

Meridian Mobile (Артем Шуба)

приз смартфон HTC Mozart

Никита Львов 17 приложений

приз смартфон HTC Mozart

ШпораКайф (Рожковский Борис)

рекламный модуль в журнале MSDeveloper.RU и банер на сайте журнала

Валентинки (Виноградов Игорь)

рекламный модуль в журнале MSDeveloper.RU

Алексей Калачев 8 приложений

рекламный модуль в журнале MSDeveloper.RU и банер на сайте журнала

Давид Кацуро и ArtMosby 7 7 приложений

рекламный модуль в журнале MSDeveloper.RU

ПОБЕДИТЕЛИ

Лучшее студенческое приложение

Самое большое количество приложений

Специальный приз от компании Microsoft

Приложение Город, Ивана Тинякова стало лучшим сразу в двух номинациях,

поэтому автор приложения получает специальный приз: смартфон Nokia Lumia 800.

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

Page 25: 03 (07) 2012 MSDeveloperRU

Internet timeРазработчик: Эрнест Полетаев

Ссылка на приложение в Marketplace

RomanToArabicРазработчик: Давид Кацуро

Ссылка на приложение в Marketplace

Moving NumbersРазработчик: Романов Алексей

Ссылка на приложение в Marketplace

ТАБЛИЦА УЧАСТНИКОВ КОНКУРСАГород Разработчик: Иван Тиняков

Ссылка на приложение в Marketplace

pool8barРазработчик: Alexandr Fursa

Ссылка на приложение в Marketplace

7788 заказ таксиРазработчик: Алексей Страх

Ссылка на приложение в Marketplace

RuBogBitРазработчик: Василий Черемисинов

Ссылка на приложение в Marketplace

Meridian MobileРазработчик: Артем Шуба

Ссылка на приложение в Marketplace

EasyKillРазработчик: Владимир Суховерхий

Ссылка на приложение в Marketplace

Коды регионов РФРазработчик: Сергей Москвин

Ссылка на приложение в Marketplace

ШпораКайфРазработчик: Борис Рожковский

Ссылка на приложение в Marketplace

Legal ConverterРазработчик: Борис Рожковский

Ссылка на приложение в Marketplace

The Ring 6Разработчик: Владимир Суховерхий

Ссылка на приложение в Marketplace

Sport ReaderРазработчик: Давид Кацуро

Ссылка на приложение в Marketplace

ПДД РФРазработчик: Sly Lamb

Ссылка на приложение в Marketplace

Такси РыбинскаРазработчик: Антон Ленев

Ссылка на приложение в Marketplace

Bubble EyesРазработчик: XIMAD Inc.

Ссылка на приложение в Marketplace

ЗадолбалиРазработчики: М. Галушко и А. Краковецкий

Ссылка на приложение в Marketplace

gTongueРазработчик: Павел Голуб

Ссылка на приложение в Marketplace

РазговорникРазработчик: ArtMosby

Ссылка на приложение в Marketplace

Euro 2012Разработчик: Андрей Тимченко

Ссылка на приложение в Marketplace

PhoneDictРазработчик: Аверченков Роман

Ссылка на приложение в Marketplace

The GuardianРазработчик: Mike Lordow

Ссылка на приложение в Marketplace

ВалентинкиРазработчик: Виноградов Игорь

Ссылка на приложение в Marketplace

СловоигрыРазработчик: Алексей Калачев

Ссылка на приложение в Marketplace

InstaCamРазработчик: Дмитрий Манаев

Ссылка на приложение в Marketplace

Музыка Нового ГодаРазработчик: Sly Lamb

Ссылка на приложение в Marketplace

Christmas MusicBoxРазработчик: Sly Lamb

Ссылка на приложение в Marketplace

ДиафильмыРазработчик: Александр Калиновский

Ссылка на приложение в Marketplace

О чем говорят цветыРазработчик: Игорь Виноградов

Ссылка на приложение в Marketplace

CongratulICEРазработчик: Алексей Калачев

Ссылка на приложение в Marketplace

LittleArcРазработчик: LittleArc

Ссылка на приложение в Marketplace

Курсы ВалютРазработчик: Вадим Жилинков

Ссылка на приложение в Marketplace

GuessTheNumberРазработчик: Давид Кацуро

Ссылка на приложение в Marketplace

Page 26: 03 (07) 2012 MSDeveloperRU

История РоссииРазработчик: Евгений Кузьмичев

Ссылка на приложение в Marketplace

Run Santa! Run! FreeРазработчик: Иван Андреев

Ссылка на приложение в Marketplace

MSdevBlogsNewsРазработчик: Давид Кацуро

Ссылка на приложение в Marketplace

ЖминацветРазработчик: Алексей Калачев

Ссылка на приложение в Marketplace

CompleShakeРазработчик: Алексей Калачев

Ссылка на приложение в Marketplace

Наши именаРазработчик: Алексей Калачев

Ссылка на приложение в Marketplace

Dark ViewerРазработчик: Эрнест Полетаев

Ссылка на приложение в Marketplace

ПивоРазработчик: Михаил Сарычев

Ссылка на приложение в Marketplace

Head HunterРазработчик: Юрий Найденов

Ссылка на приложение в Marketplace

ProgrammizmРазработчик: Сергей Урусов

Ссылка на приложение в Marketplace

Undead CarnageРазработчик: PixelsFury

Ссылка на приложение в Marketplace

NewsRU.comРазработчик: Давид Кацуро

Ссылка на приложение в Marketplace

ОрфоСРазработчик: Роман Аверченков

Ссылка на приложение в Marketplace

ВВЛРазработчик: Роман Аверченков

Ссылка на приложение в Marketplace

Толковый СловарьРазработчик: Роман Аверченков

Ссылка на приложение в Marketplace

MsnbcWorldNewsРазработчик: Давид Кацуро

Ссылка на приложение в Marketplace

My ShowsРазработчик: Иван Калашников

Ссылка на приложение в Marketplace

Microsoft Student Partner BlogРазработчик: Александр Трусов

Ссылка на приложение в Marketplace

TransliteРазработчик: Давид Кацуро

Ссылка на приложение в Marketplace

Поздравления с 14 февраляРазработчик: Константин Тогой

Ссылка на приложение в Marketplace

Love MusicРазработчик: Sly Lamb

Ссылка на приложение в Marketplace

Цитаты о любвиРазработчик: ArtMosby

Ссылка на приложение в Marketplace

ПодаркиРазработчик: ArtMosby

Ссылка на приложение в Marketplace

Love WallpapersРазработчик: ArtMosby

Ссылка на приложение в Marketplace

Photo LoveРазработчик: ArtMosby

Ссылка на приложение в Marketplace

Признания в любвиРазработчик: ArtMosby

Ссылка на приложение в Marketplace

Test Of Love FreeРазработчик: Михаил Сарычев

Ссылка на приложение в Marketplace

Bubble LoveРазработчик: Михаил Сарычев

Ссылка на приложение в Marketplace

BashOrgReaderMeРазработчик: Ирек Нигматуллин

Ссылка на приложение в Marketplace

Gem CurseРазработчик: Дмитрий Фокин

Ссылка на приложение в Marketplace

Location trackingРазработчик: Константин Панков

Ссылка на приложение в Marketplace

Ape The WallРазработчик: XIMAD Inc.

Ссылка на приложение в Marketplace

И-ЦЗИНРазработчик: Николай Кобзев

Ссылка на приложение в Marketplace

Flower WallpapersРазработчик: ArtMosby

Ссылка на приложение в Marketplace

Штрафы ПДДРазработчик: Вадим Жилинков

Ссылка на приложение в Marketplace

GPS SpeedРазработчик: Вадим Жилинков

Ссылка на приложение в Marketplace

Page 27: 03 (07) 2012 MSDeveloperRU

Электронное ЗдоровьеРазработчик: Александр Трусов

Ссылка на приложение в Marketplace

Сонник МиллераРазработчик: Роман Аверченков

Ссылка на приложение в Marketplace

Пятнашки-ВкусняшкиРазработчик: Rocketrock

Ссылка на приложение в Marketplace

РосЯмаРазработчик: Ильдар Мусалямов

Ссылка на приложение в Marketplace

E-xxxРазработчик: Роман Аверченков

Ссылка на приложение в Marketplace

ExBYRatesРазработчик: Сергей Урусов

Ссылка на приложение в Marketplace

Выборы 2012Разработчик: Алексей Арефьев

Ссылка на приложение в Marketplace

NBA_com_ReaderРазработчик: Александр Трусов

Ссылка на приложение в Marketplace

Zuminja FreeРазработчик: XIMAD Inc.

Ссылка на приложение в Marketplace

Lovely WallpapersРазработчик: Artem Gandzioshyn

Ссылка на приложение в Marketplace

Игра БашеРазработчик: Алексей Калачев

Ссылка на приложение в Marketplace

КроссПоздравлениеРазработчик: Алексей Калачев

Ссылка на приложение в Marketplace

AtomixРазработчик: Denis Osipov

Ссылка на приложение в Marketplace

#новостиРазработчики: М. Галушко и А. Краковецкий

Ссылка на приложение в Marketplace

Linux ReaderРазработчик: Никита Львов

Ссылка на приложение в Marketplace

Limonov ReaderРазработчик: Никита Львов

Ссылка на приложение в Marketplace

Thinketg ReaderРазработчик: Никита Львов

Ссылка на приложение в Marketplace

LinuxGid ReaderРазработчик: Никита Львов

Ссылка на приложение в Marketplace

Решение уравнений методом КрамераРазработчик: Никита Львов

Ссылка на приложение в Marketplace

ПараллепипедРазработчик: Никита Львов

Ссылка на приложение в Marketplace

ОкружностьРазработчик: Никита Львов

Ссылка на приложение в Marketplace

Нахождение уравнения прямой (2 точки)Разработчик: Никита Львов

Ссылка на приложение в Marketplace

Скалярное произведение векторовРазработчик: Никита Львов

Ссылка на приложение в Marketplace

Площадь треугольникаРазработчик: Никита Львов

Ссылка на приложение в Marketplace

Перпендикулярность векторовРазработчик: Никита Львов

Ссылка на приложение в Marketplace

Длина вектора (по точкам)Разработчик: Никита Львов

Ссылка на приложение в Marketplace

Идеальный газРазработчик: Никита Львов

Ссылка на приложение в Marketplace

WP7Forum ReaderРазработчик: Никита Львов

Ссылка на приложение в Marketplace

Gornakov ReaderРазработчик: Никита Львов

Ссылка на приложение в Marketplace

Мифы созвездийРазработчик: Алексей Калачев

Ссылка на приложение в Marketplace

ExKAZRatesРазработчик: Сергей Урусов

Ссылка на приложение в Marketplace

Расчет угла между векторамиРазработчик: Никита Львов

Ссылка на приложение в Marketplace

ПроизводнаяРазработчик: Никита Львов

Ссылка на приложение в Marketplace

Первая помощьРазработчик: Петр Комзолов

Ссылка на приложение в Marketplace

Page 28: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 28

И нтервью

Беседовал Станислав Горнаков

Интервью с Александром Косованом основателем и генераль-ным директором «MacPaw»

Наше досье

Александр Косован ‒ главный разработчик и основатель MacPaw. После получения степени бакалавра в Киевском По-литехническом Университете в 2008 году совместно с однокурсницей Верой Ткаченко основал компанию MacPaw. Спустя несколько месяцев был выпущен первый и ныне самый известный продукт компании ‒ CleanMyMac.

К 2011 году CleanMyMac был установлен более чем на миллион Макинтошей по всему миру. Александр уверен: успех про-дукта ‒ в новом подходе к разработке пользовательских интерфейсов, ориентированных исключительно на пользователя.

Это подход был применен и в отношении Windows-платформы, и в мае 2011 года компания выпустила CleanMyPC.

Александр планирует и дальше заниматься развитием MacPaw и не ограничивает деятельность компании областью раз-работки Mac-приложений.

Не так давно мне удалось познако- миться с командой MacPaw, из- вестными разработчиками про-

стых и элегантных решений для Mac-платформы. Год назад команда выпу- стила свое первое приложение для Windows. CleanMyPC ‒ не только уни-версальное решение для очистки до-полнительного места на компьютере, но и PC-аналог их наиболее успешного Mac-продукта с аналогичным названи-ем CleanMyMac. Подобное «портирова-ние» приложений с Mac на PC ‒ непри-вычный подход в отрасли разработки, поэтому интересно было пообщаться и взять интервью у основателя и дирек-тора MacPaw Александра Косована.

Станислав Горнаков: Здравствуйте, Александр! Итак, начнем с того, что больше всего заинтересо-вало редакцию журнала MSDeveloper.RU: как ко-манде разработки Mac-приложений пришла идея сделать Windows-продукт CleanMyPC?

Александр Косован: Пользователи компьютеров, независимо от платфор-мы, часто сталкиваются с нехваткой места на своих накопителях. Однако очистка ненужных файлов вручную ‒ дело достаточно рутинное и требую-щее глубоких познаний в архитектуре операционной системы. Поэтому суще- ствует необходимость автоматизиро-ванного решения. Так появился Clean-MyMac. В отличие от других похожих решений, CleanMyMac не только эф-фективен, но и представляет собой абсолютно новый, простой и понятный подход в решении задач. Судите сами: все, что нужно сделать, чтобы очистить место ‒ нажать кнопку Сканировать и затем Очистить. Затем мы поняли, что подобный подход еще более вос-требован в Windows-среде и решили портировать программу на ПК. Хотя, как правило, все двигаются в обратном направлении.

А как же команде Mac-разработчиков удалось на-писать полноценную систем-ную утилиту для Windows?

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

Иными словами, в компании две команды разработки приложений - под Mac и PC?

?

??

u

Page 29: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 29

И нтервью

Абсолютно верно. Они даже сидят в разных офисах и испытывают к друг другу классовую неприязнь (шутя).

А как же совместная работа над, фактически, одним продуктом для разных плат-форм?

Разумеется, при первичном проектиро-вании и разработке CleanMyPC была задействована вся команда Mac-разра-ботчиков. Ведь они уже много лет ра-ботают и полируют CleanMyMac и не понаслышке знают о том, как люди ис-пользуют подобные приложения и ка-кими они должны быть.

И какими же должны быть подобные предложения?

В первую очередь, они должны рабо-тать эффективно, иными словами, ос-вобождать действительно много места. Чем больше памяти может очистить программа ‒ тем более она востребо-вана, и эту закономерность мы наблю-даем как на Mac, так и на PC.

Это звучит несколько... оче-видно.

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

А в чем выражается «про-стой и понятный» подход CleanMyMac в разработке CleanMyPC?

При создании графического интерфей-са CleanMyPC мы опирались на внеш-ний вид и структуру нашего Mac-при- ложения. Это наиболее синхронная часть продукта. В разработке CleanMy- PC мы пошли по проторенной CleanMy-Mac’ом дорожке ‒ чтобы гарантировать

?

?

?

?

u

Page 30: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 30

И нтервью

сохранность и работоспособность всех приложений и самой операционной си-стемы, работа с приложением сведена к алгоритму:

{ Просканировал.

{ Очистил.

Что касается «начинки», то функции, сервисы, способы очистки, логика по-иска файлов в обеих системах карди-нально различаются, и изнутри Clean-MyMac и CleanMyPC ‒ два совершенно разных приложения.

Оказался ли CleanMyPC успешнее его Mac-версии?

Нельзя сказать однозначно. Самое глав- ное, что мы усвоили для себя ‒ это то, что Windows-рынок кардинально от-личается от Mac-рынка. Особенно это касается таких утилит, как CleanMyPC, здесь очень жесткая конкуренция, и подход к покупателям совсем другой. Впрочем, именно наш «пользователь-ский подход» Windows-пользователям очень нравится.

Каковы будущие планы от-носительно CleanMyPC?

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

Хотите оставить одну кнопку для пользователя, как в iPhone?

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

Вы хорошо разобрались в потребностях пользовате-лей, а как насчет потребно-стей Windows-среды? Какую платформу для разработки вы выбрали и почему?

Для реализации была выбрана плат-форма .NET 3.0. Это самая удобная и гибкая платформа, использующаяся в разработке сложных графических ин-терфейсов, таких, как в CleanMyPC. Основные преимущества .NET 3.0 ‒ высокая скорость разработки и воз-можность создания rich-интерфейсов (с векторной графикой и анимацией), как на Cocoa. На С++ процесс разра-ботки занял бы намного больше вре-

мени. Дополнительным стимулом был тот факт, что .NET 3.0 есть в системе по умолчанию, начиная с Windows Vista, и потому его не надо дополнительно устанавливать, в отличие от пока мало распространенного .NET 4.0. Мы рас-сматривали также .NET 2.0, ведь она доступна и на Windows XP, но в ней еще нет WPF (инструменты создания графического интерфейса) и WCF, не-обходимого для работы с сервисами слежения за системными процессами.

Выбор в пользу .NET 3.0 продиктовал свои условия ‒ пришлось провести большую работу по внедрению части технологий из более поздних поколе-ний фреймворков (таких как .NET 4.0). К примеру, то, что в .NET 4.0 можно ис-пользовать с помощью одной строки кода, нам приходилось реализовывать заново тридцатью строками. Большин-ство элементов управления, которые вы видете в CleanMyPC ‒ вложенные списки файлов, кнопки, полосы про-крутки и прочее ‒ мы писали и настра-ивали сами.

А с точки зрения сред разработки, что удобнее - Xcode или Visual Studio?

Здесь впору ответить «На вкус и цвет товарища нет», поскольку это такой же вопрос предпочтений, как и выбор между WP7 и iPhone. Уверен, если по-садить опытного Cocoa-разработчика за Visual Studio, он будет долго подби-рать слова, чтобы описать охвативший его ужас. С другой стороны, если опыт-ный .NET разработчик станет изучать Xcode, его энтузиазм также сойдет на нет в считанные секунды. Обе среды отлично справляются со своими зада-чами, постоянно развиваются и совер-шенствуются.

Как вы оцениваете - легче разрабатывать под Windows или под Mac? u

?

?

?

?

?

?

Page 31: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 31

И нтервью

Это непростой вопрос. Надо признать-ся, возможности работы с графикой средствами WPF еще уступают тому, что можно реализовать на Cocoa. И, на мой взгляд, это основной вызов для Microsoft. Сейчас армия пользователей пополняется прежде всего новичками, а для них простота и понятность графи-ческого интерфейса обязательна.

На сегодня .NET 3.0 ‒ самая подходя- щая платформа для разработки по-пулярного программного обеспечения. .NET 4.0 еще недостаточно распро-странена. .NET 4.5 ‒ еще совсем «сы-рая», да и Microsoft предлагает ее исключительно с целью разработки Metro-приложений для нового Windows Store. Впрочем, если Microsoft серьезно смотрит в сторону закрытия платфор-мы и перехода на Metro-приложения, то .NET 4.5, очевидно, скоро станет основным фреймворком для решения задач разработчиков.

Неоспоримое преимущество работы в Windows ‒ это наличие подробной до-кументации, массы форумов и готовых решений. В отличие от разработки на Mac, здесь почти не приходится изо-бретать велосипеды.

Скоро выходят новые поко-ления ОС - OS X Mountain Lion и Windows 8, где во многом разработчики станут еще более ограничены в сред-ствах. Не боитесь ли вы, что ваши продукты потеряют свой рынок?

Оптимизация, чистка, поиск ненужных файлов ‒ эти действия концептуально противоречат цели любой операцион-ной системы. Все же знают, что для iOS и Windows Phone, к примеру, таких про-грамм нет.

Свою цель разработчики ОС, будь то Мас или Windows, видят в создании универсальной, стабильной, надежной операционной системы, которая не тормозит, не зависает, в ней ничего не нужно «оптимизировать» ‒ она просто работает. Преследуя эти цели Apple и Microsoft последние годы движутся к закрытию своих систем, разработке так называемых «песочниц» для при-ложений и процессов. В конце концов, необходимость в таких приложениях как CleanMyMac и CleanMyPC отпадет, по крайней мере, в том виде, в котором они есть сейчас.

И что вы планируете тогда делать?

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

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

Конечно, в идеале решения подобных проблем должны быть встроены в си-стему, но разработка операционной си-стемы ‒ это большой проект, которым занимается большой коллектив. Внесе-ние подобных изменений может зани-мать годы. За такое время небольшая компания может не только выявить и понять проблему, но и выпустить ре-шение для нее. Насколько небольшая? Ну, как MacPaw :)

Похоже, вы нашли свою формулу успеха! Желаем вам успехов в ваших буду-щих начинаниях! n

?

?

?

Page 32: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 32

Р азработка

Целые vs GUID vs Естественные и Суррогатные ключи

ПереводчикАндрей Гордиенков[email protected]://softblog.violet-tape.ru/г. Москва

АвторДжонатан Оливер (Jonathan Oliver)Сайт: http://blog.jonathanoliver.comТвиттер: @jonathan_oliver

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

ного первичного ключа из вариантов, представленных в заголовке. Что бу-дет лучше: выбрать естественный или суррогатный ключ? Если мы выбира-ем суррогатный ключ то, что выбрать: целочисленный ряд или же GUID? В прошлом мне пришлось с жаром отста-ивать все точки зрения, так что могу рассмотреть плюсы и минусы каждого подхода.

Естественный vs Суррогатный ключи

Джо Целко (Joe Celko) утверждает, что мы должны использовать естественные ключи, созданные из атрибутов записи, а не заниматься присвоением произ-вольных значений записям в таблицах. Я согласен с ним. Но! В то же время мы должны стараться хранить ключи лег-кими/маленькими, вместо того, чтобы создавать массивные составные клю-чи, чьи значения в свою очередь долж-ны будут храниться в других таблицах для возможности соединения таблиц, поддержания их целостности. Как я выбираю какой способ использовать? Легко, я использую оба.

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

Целочисленный ряд vs GUID

Прежде чем начнем, могу я попросить

произносить «GUID» как «гуид», а не «гуайди»? Кстати, это тоже предмет жарких споров, но ирония в том, что лагерь борцов за суррогатные ключи борется против себя же.

В моей практике было активное ис-пользование обоих вариантов, однако в последнее время нарисовался побе-дитель по всем статьям, и это – GUID.

Главным аргументом в этой баталии долгое время оставался размер ключа. 4 байта для Int и 16 байт для GUID. Да, GUID занимает 16 байт, а не 32. Основ-ным аргументом является то, что с 4х- байтными ключами база работает быст- рее. Да, действительно, использование целочисленных суррогатных ключей может быть незначительно быстрее, но при этом привносится целый комплекс неудобств связанных с самой природой целых чисел.

Еще один аргумент против GUID состоит в том, что индекс получается фраг-ментированным и сильно бьет страницы. Однако это может быть легко исправлено используя GUID «COMB».

Данный прием позволяет значитель-но увеличить производительность при вставке и объединения таблиц.

DECLARE @aGuid UNIQUEIDENTIFIER

SET @aGuid = CAST(CAST(NEWID() AS BINARY(10))

+ CAST(GETDATE() AS BINARY(6)) AS UNIQUEIDENTIFIER)

Результат, полученный с помощью дан-ного кода:

E25AFE33-DB2D-4502-9BF0-919001862D20

83E689D3-8549-4094-B223-

919001862D20

CC22A56D-0CD5-43C5-990E-919001862D20

D5149998-1718-468C-B1AD-919001862D20

CBD0182D-4A0E-40AC-9A4C-919001862D20

Да, последний блок схожий, но это по-тому, что они были сформированы в одно время. Разрешающая способ-ность по времени у SQL сервера в рай-оне 1/300 секунды.

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

Далее, как часто в результате опера-ции select+join вы планируете получать десятки тысяч или миллионы строк в ответ, когда действительно важна роль типа первичного ключа? Однако чаще всего требуются десятки и сотни строк для работы пользователя, и в дальней-шем узким местом является не работа по сравнению ключей, а построение всех нужных ассоциаций и создание новых объектов.

Следующим аргументом за GUID явля-ется то, что в любой средней/большой системе, как например PayPal, eBay и так далее, требуется использовать 8и-байтовое число, т.е. BigInt, в против-ном случае вы достаточно быстро ис-черпаете все уникальные значения для хранения данных.

Бывали ли у вас случаи, когда необ-ходимо было быстро перевести схе-му базы на 8и-битные значения? Не-большая процессинговая компания Authorize.Net использовала знаковое целое, но когда дела пошли в гору, им пришлось рассылать уведомления всем своим заказчикам. Повезло тем, u

Page 33: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 43

Р азработка

Рекл

ама

кто трактовал все данные от компании как строку, тех изменения не затронули, но остальным пришлось так или иначе попотеть. Думаете ваше приложение никогда не будет столь велико и попу-лярно? Я надеюсь, что все мои про-екты будут удачны, так что планирую соответствующе.

Третьей причиной, самой явной и се-рьезной для меня является то, что в 100% распределенных системах же-лательно полностью избежать единой точки выдачи уникальных ключей. Опе-рируя GUID вместо целых чисел, мож-но переложить генерирование уникаль-ных идентификаторов на приложение. Сохранять объекты в базу сразу, не выполняя дополнительных действий по синхронизации уникальных ключей генерируемых базой – что освобождает немалые ресурсы. Такой подход так же позволяет использовать «временно со-единяемые системы».

В четвертых, использование GUID до-бавляет в приложение «безопасность по незнанию». Примерно два года на-зад мы заказали несколько машин у Dell. Когда дело дошло до финальной страницы, я заметил, что параметр в URL был в духе «&orderId;=12345678». Ради интереса я вычел единицу и об-новил страницу. Не ожидал, но все же я увидел чей-то заказ, который был совершен несколько минут назад. Там присутствовали все реквизиты, адреса, и прочая «чувствительная» информа-ция. На мгновение мелькнула мысль, что можно написать скрипт и собрать информацию обо всех заказчиках, так как на сайте не было нормальной авто-ризации. Конечно, это глупая ошибка, которую вы, скорее всего, избежите, но использование GUID дает дополни-тельную защиту.

Пятое ‒ использование GUID позволяет убедиться в том, что вы верно пишете свои запросы с объединениями таблиц. Так как при использовании целых чисел в качестве ключей, с очень большой вероятностью произойдут случайные совпадения, GUID позволят указать на ошибки запросов.

Итого

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

Windows 8 Consumer Preview — это предварительная версия программного обеспечения, в которую могут быть внесены значительные изменения до момента выпуска официаль-ной версии. Корпорация Майкрософт не предоставляет каких-либо гарантий, прямых или косвенных, в отношении указанной здесь информации. Для некоторых функций продукта может потребоваться дополнительное оборудо-вание или программное обеспечение. Если необходимо вернуться к предыдущей операционной системе, потре-буется переустановить ее с носителя для восстановления системы или с установочного диска, который входит в ком-плект поставки компьютера.

Скачать Windows 8 Consumer Preview

Page 34: 03 (07) 2012 MSDeveloperRU

Февральский бюллетень обновлений центра загрузки Microsoft

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

Примечание: каждый понедельник в 10 часов утра мы публикуем на сайте журнала еженедельный бюллетень обновлений центра загрузок Microsoft.

c MVP Session 8: Dynamically Link Business Data to Shapes in Visio 2010 (working files)c Microsoft Lync 2010 Phone Edition for HP 4110 and HP 4120c Best Practices for Virtualizing Exchange Server 2010 with Windows Server® 2008 R2 Hyper V™c Microsoft AppFabric 1.1 for Windows Server Caching Best Practices Analyzer (BPA) Toolc Microsoft Dynamics AX 2012 System Requirementsc Flexible Authentication in Microsoft Dynamics AX 2012c Migrate from Exchange Public Folders to Microsoft Office 365c Test Lab Guide: Demonstrating Call-based Extensible Connectivity 2.0 Management Agentsc Office 365 Single Sign-On with AD FS 2.0 whitepaperc BI Image X: SQL 2012 RC0c Microsoft Application Virtualization (App-V) Documentation Resources Download Pagec Windows Management Framework 3.0 - Betac Microsoft Visual Studio 11 Beta Shell (Integrated)c Microsoft® .NET Framework® 4.5 Betac Internet Information Services (IIS) 7.5 Expressc Understand and Troubleshoot Virtualized Domain Controller (VDC) in Windows Server «8» Betac Lync Server 2010 Hotfix KB 2493736c Visual Studio 11 Beta Update Filesc Windows Azure Libraries for Java 0.2 February 2012 CTPc Microsoft Lync 2010 Phone Edition for Polycom CX700 and LG-Nortel IP Phone 8540c Windows 8 Consumer Preview Product Guide for Businessc Microsoft Lync Server 2010 Multitenant Pack for Partner Hosting Deployment Guidec Reference Architecture for the Microsoft Lync Server 2010 Multitenant Pack for Partner Hostingc A Microsoft Lync Server 2010 Multitenant Pack for Partner Hosting Reference Architecture Case Studyc Test Lab Guide-Deploying RD Licensingc Creating Continuously Available File Shares with Windows Server “8” Betac Application Compatibility and API Support for SMB 2.2, CSVFS, and ReFSc Microsoft Visual Studio 11 Beta Visualization & Modeling SDKc Microsoft DirectAccess Connectivity Assistant 2.0 Betac Lync Server 2010 Group Chat Hotfix KB 2670342c Lync 2010 Group Chat Admin Tool Hotfix KB 2672318c Lync 2010 Hotfix KB 2670326 (64 bit)c Lync 2010 Hotfix KB 2670326 (32 bit)c Lync 2010 Group Chat Hotfix KB 2672325c Microsoft Security Intelligence Report Special Edition: 10-Year Reviewc Microsoft Dynamics AX 2012 Upgrade Guidec Test Lab Guide: Base Test Lab Guide for Windows Server «8» Betac Microsoft® SQL Server® Compact 4.0 SP1 - Community Technology Preview 1 (CTP1)c Visual Studio Team Foundation Server 11 Installation Guidec IntelliTrace Collector for Visual Studio 11 Betac Microsoft® .NET Framework® 4.5 Beta Language Packc Test Lab Guide: Demonstrate Remote Desktop Services in

Windows Server «8» Betac Test Lab Guide: Demonstrate Remote Desktop Services Desktop Virtualization in Windows Server «8» Betac Understand and Troubleshoot Servicing in Windows Server «8» Betac Understand and Troubleshoot BitLocker in Windows Server «8» Betac Test Lab Guide: Demonstrate High Availability Printing in Windows Server «8» Betac Test Lab Guide: Demonstrate Virtualized Domain Controller (VDC) in Windows Server «8» Betac Test Lab Guide: Demonstrate ADDS Simplified Administration in Windows Server «8» Betac System Center Monitoring Pack for System Center 2012 Configuration Manager - Release Candidatec Microsoft Exchange RPC Extractor 1.0c Test Download for Kits - English pagec Extensible Application Markup Language (XAML)c Open Specifications Preview Specificationsc Windows MultiPoint Server 2011 Planning Guidec Microsoft Lync Server 2010 Capacity Calculatorc Update for Windows Thin PC (KB2570814)c Update for Windows Thin PC (KB2502664)c Update for Windows Thin PC (KB2539566)c Requirements for Windows Server App Certification Programc Microsoft SQL Server Data Portability Documentationc Windows Server App Certification Kit (SCK) betac SQL Server Standards Support Documentationc Microsoft SQL Server Protocol Documentationc Tagged Objects for Surface 2.0 Whitepaperc Update for Windows Thin PC (KB2664186)c Update for Windows Embedded POSReady 7 (KB2663820)c Update for Windows Thin PC (KB2649672)c WHDC White Papers and Documentationc Update for Windows Thin PC (KB2645895)c Technical reference for Microsoft SharePoint Server 2010c Internet Explorer Standards Documentationc Microsoft® Codename Trust Services Samplesc Quick Start Guide for Outlook Voice Access 2010c Microsoft Dynamics AX 2012 White Paper: Report Programming Modelc Microsoft adCenter Desktopc Client Virtualization in Microsoft Lync 2010c Storage Calculators for System Center Data Protection Manager 2010c MVP Session 7: Work with and Customize Shape Data in Visio 2010 (working file)c Office 365 for professionals and small businesses Service Descriptionc Office 365 for Enterprise Service DescriptionsMicrosoft Exchange Server 2010 SP2 Language Pack Bundlec Biztalk Terminatorc Test Lab Guide: Demonstrate IPv6c Exchange Web Services Managed API 1.2c WHDC White Papers and Documentationc Microsoft Volume Licensing Service Center (VLSC) User Guide

Page 35: 03 (07) 2012 MSDeveloperRU

c Infrastructure Planning and Designc HPC Pack 2008 R2 Service Pack 3c System Center Monitoring Pack for SQL Azure - CTPc SOA Applications, Infrastructure and Management with Windows® HPC 2008 R2c Office 365 for Enterprise Service Descriptionsc Prism 4.1 - February 2012c Office 365 for professionals and small businesses Service Descriptionc Calendar Checking Tool for Outlookc Team Foundation Installation Guide for Visual Studio Team System 2008c Hotfix for .NET Framework 3.5.1 - Windows Vista Service Pack 2/Windows Server 2008 Service Pack 2 - KB2637518c Hotfix for Microsoft .NET Framework 3.5.1 on Windows 7 RTM and Windows Server 2008 R2 RTMc Hotfix for Microsoft .NET Framework 3.5.1 on Windows 7 Service Pack 1 and Windows Server 2008 R2 Service Pack 1c Microsoft Outlook Configuration Analyzer Toolc Connecting SharePoint 2010 to Line-of-Business Systems to Deliver Business-Critical Solutionsc SharePoint 2010: IT Pro Evaluation Guidec Microsoft® Codename «Data Transfer» Terms of Usec Monitoring Applications via Windows Phone 7.5 Devices and the Cloudc K2 - Streamlining the Onboarding of New Clients and Matters - LegalTech 2012c Microsoft Product Use Rights Explainedc ASP.NET MVC 4 Betac Volume Licensing Program Guides, Datasheets, and FAQsc Windows Embedded Compact 7 Evaluation Editionc Microsoft Dynamics CRM 2011 Implementation Guidec Windows Embedded Silverlight Toolsc Windows Embedded Compact 7 Monthly Update January 2012c Update for Microsoft Office Outlook 2003 Junk Email Filter (KB2597968)c Microsoft® Windows® Malicious Software Removal Tool (KB890830) x64c Microsoft® Windows® Malicious Software Removal Tool (KB890830)c Update for Windows 7 (KB2640148)c Update for Windows Server 2008 R2 for Itanium-based Systems (KB2640148)c Update for Windows 7 for x64-based Systems (KB2640148)c Update for Windows Server 2008 R2 x64 Edition (KB2640148)c Update for Windows Mail Junk E-mail Filter for x64-based Systems [February 2012] (KB905866)c Update for Windows Mail Junk E-mail Filter [February 2012] (KB905866)c Windows Azure Training Kit - January Refreshc Update for Microsoft Office 2010 (KB2597091) 32-Bit Editionc Update for Microsoft Office 2010 (KB2597091) 64-Bit Editionc Update for Microsoft Office 2007 suites (KB2597120)c February 2012 Security Release ISO Imagec Open Specifications Preview Specificationsc Multi-Tenancy and Hosting Guidance for Exchange Server 2010 SP2c Update for Windows 7 (KB2639308)c Security Update for Windows 7 (KB2654428)c Update for Windows Server 2003 (KB2657025)c Update for Windows Server 2008 R2 for Itanium-based Systems (KB2640696)c Update for Windows XP x64 Edition (KB2657025)c Microsoft® Codename Trust Services SDK and Management Toolc Open Specifications Preview Specificationsc Microsoft® Surface® 2.0 SDK and Runtime (Updated

February 2, 2012)c Digital Citizenship Toolkit - Brochures, Factsheets & Tip Cardsc Microsoft® Codename Trust Services Terms of Usec Microsoft® Codename Trust Services Samplesc SharePoint 15 Technical Preview Interoperability API Documentationc Microsoft Computing Safety Indexc Lync 2010 Bandwidth Calculatorc Migrating from Exchange Server 2010 in Hosting Mode to Exchange Server SP2c Hands-On Labs for Enterprise Library 5.0 Integration Pack for Windows Azurec System Center Monitoring Pack for Microsoft SQL Server 2008 R2 Parallel Data Warehouse Appliancec Calendar Checking Tool for Outlookc Viewers for Windows Embedded Compact 7 - Microsoft Office 97, 2000, 2003, XP and 2007 file format supportc Bing Spatial Data Services SDK (PDF)c Bing Spatial Data Services SDK (CHM)c SCDPM 2010 Interoperability Hotfix for Centralized Management, with System Center Data Protection Manager 2012 Betac PCI Implementation Guide for Microsoft Dynamics AX 2012 Feature Packc Microsoft Dynamics AX 2012 Upgrade Script Referencec Microsoft Communicator for Mac 2011 13.1.3 Updatec Kinect for Windows SDK v1.0c Windows MultiPoint Server 2011 Deployment Guidec Windows Azure Libraries for Java 0.1 December 2011 CTPc Retail Scheduler Technical Reference for Microsoft Dynamics AX 2012 Feature Packc Compact Hiring Process sample diagram for Visio 2010c The WMI Diagnosis Utility -- Version 2.1c What’s New in Microsoft Dynamics AX 2012 Feature Pack for Retailc Align and distribute shapes in Visio 2010c Exchange Server 2010 SP2 Helpc Retail Deployment Guide for Microsoft Dynamics AX 2012 Feature Packc Microsoft Dynamics AX 2012 Upgrade Guidec Microsoft Dynamics ERP Software License Termsc Retail Store Connect Technical Reference for Microsoft Dynamics AX 2012 Feature Packc Microsoft Dynamics AX 2012 Guide: Installationc New, Changed, and Deprecated Features for Microsoft Dynamics AX 2012c Microsoft Dynamics AX 2012 Privacy Statementc Microsoft Dynamics AX 2012 System Requirementsc Microsoft Lync Server 2010 Support for Large Meetingsc FOPE-EHA Support Contact Information and Support SLO Detailsc Accessibility: A Guide for Government Organizationsc Upgrade worksheet for SharePoint Server 2010c Microsoft Work Group Server Protocol Program License Agreement (Patent Only) for Development and Product Distributionc Update for Windows Thin PC (KB2649672)c Update for Windows Embedded POSReady 7 (KB2645895)c Update for Windows Embedded POSReady 7 (KB2502664)c Virtual Machine Manager (VMM) for System Center 2012 Release Candidate Documentationc Solution Accelerators Marketing Resourcesc Microsoft Exchange Server Protocol Documentationc Microsoft Exchange and Microsoft Outlook Standards Documentationc Microsoft SharePoint Products and Technologies Protocol Documentation n

Page 36: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 36

S ilverlight

АвторВалерий Воробьев Блог: www.vvorobjev.ruРазработчикг. Москва

Создание Twitter клиента на Silverlight\WPFВторая часть

Разработка модуля информации

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

Итак, добавим в проект InfoModule три папки Models, Views, ViewModels. Так же нам потребуется добавить ссылки на Mi- crosoft.Practices.Prism, Microsoft.Practices.Unity.Sil- verlight и библиотеку классов Infrastructure.

Добавим в папку Views новое представление, назовем его InfoView. Ниже приведена разметка только что добавленно-го представления.

<UserControl x:Class=”InfoModule.Views.InfoView” xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”> <Grid x:Name=”LayoutRoot”> <Grid.RowDefinitions> <RowDefinition Height=”Auto” /> <RowDefinition Height=”Auto” /> <RowDefinition Height=”Auto” /> </Grid.RowDefinitions>

<StackPanel Grid.Row=”0” Orientation=”Vertical” Margin=”0,0,0,10”> <StackPanel Orientation=”Horizontal”> <TextBlock Text=”Читает” Margin=”0,0,0,4” FontSize=”20” /> <TextBlock Text=”{Binding Path=UserInfo.FriendsCount, Mode=TwoWay}” Margin=”6,0,0,4” FontSize=”20” Foreground=”CornflowerBlue” /> </StackPanel> <ListBox HorizontalAlignment=”Stretch” ItemsSource=”{Binding Path=FriendList}” MaxHeight=”250” > <ListBox.ItemTemplate> <DataTemplate> <Border CornerRadius=”6” Margin=”2” Padding=”4” BorderThickness=”2” Border- Brush=”SteelBlue” Width=”300”> <StackPanel Orientation=”Vertical” > <StackPanel Orientation=”Horizontal” > <Image Source=”{Binding Path=ProfileImageUrl}” Margin=”2” /> <TextBlock VerticalAlignment=”Center” Text=”{Binding Path=Name}” Mar- gin=”2” /> </StackPanel> <TextBlock Text=”{Binding Path=Description}” Margin=”2” TextWrapping=”Wrap” TextAlignment=”Left” /> <TextBlock Text=”{Binding Path=Location}” Margin=”2” /> </StackPanel> </Border> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </StackPanel>

<StackPanel Grid.Row=”1” Orientation=”Vertical”> <StackPanel Orientation=”Horizontal”> u

Page 37: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 37

S ilverlight

<TextBlock Text=”Читатели” Margin=”0,0,0,4” FontSize=”20” /> <TextBlock Text=”{Binding Path=UserInfo.FollowersCount, Mode=TwoWay}” Margin=”6,0,0,4” FontSize=”20” Foreground=”CornflowerBlue” /> </StackPanel> <ListBox HorizontalAlignment=”Stretch” ItemsSource=”{Binding Path=FollowerList}” MaxHeight=”250” > <ListBox.ItemTemplate> <DataTemplate> <Border CornerRadius=”6” Margin=”2” Padding=”4” BorderThickness=”2” Border- Brush=”SteelBlue” Width=”300”> <StackPanel Orientation=”Vertical” > <StackPanel Orientation=”Horizontal” > <Image Source=”{Binding Path=ProfileImageUrl}” Margin=”2” /> <TextBlock VerticalAlignment=”Center” Text=”{Binding Path=Name}” Mar- gin=”2” /> </StackPanel> <TextBlock Text=”{Binding Path=Description}” Margin=”2” TextWrapping=”Wrap” TextAlignment=”Left” /> <TextBlock Text=”{Binding Path=Location}” Margin=”2” /> </StackPanel> </Border> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </StackPanel>

</Grid></UserControl>

В разметке присутствуют два элемента StackPanel. Первая панель содержит список друзей, а вторая ‒ список последователей.

Добавим в папку ViewModels новый класс. Назовем его InfoViewModel. Ниже приведен код модели представления InfoView-Model.

namespace InfoModule.ViewModels{ public class InfoViewModel : NotificationObject { private readonly IRegionManager _regionManager; private readonly string _userId;

public InfoViewModel(IRegionManager regionManager) { if (regionManager == null) throw new Exception(“regionManager”);

_regionManager = regionManager;

IRegion loginRegion = _regionManager.Regions[“LoginRegion”];

if (loginRegion != null) { string[] values = loginRegion.Context.ToString().Split(‘=’, ‘&’); // Сохраняем id авторизовавшегося пользователя, чтобы в дальнейшем запросить информацию об учетной записи _userId = values[5];

}

// Инициализация списка последователей FollowerList = new ObservableCollection<User>(); // Инициализация списка друзей FriendList = new ObservableCollection<User>();

// Получаем информацию о себе :) GetUser(_userId);

// Получаем список пользователей, которых читаем GetUserList(“friends”, FriendList);

// Получаем список подписчиков GetUserList(“followers”,FollowerList); }

#region GetUser

private void GetUser(string userId) { // Создаем пользователя (тип User описан в библиотеке Infrastructure)

Page 38: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 38

S ilverlight

UserInfo = new User(); u // Запрашиваем информацию о конкретном пользователе по id // В данном случае в качестве формата возвращаемых данных используется xml, // но можно использовать и json. Для этого достаточно заменить подстроку xml на json в строке запроса. Uri userUri = new Uri(string.Format(“https://api.twitter.com/1/users/lookup.xml?user_id={0}”, userId));

WebClient client = new WebClient(); client.DownloadStringAsync(userUri); client.DownloadStringCompleted += (sender, e) => { if (e.Error == null) { // Преобразуем полученные данные в документ Xml XDocument documentXml = XDocument.Parse(e.Result); // Получаем элемент user. В данном случае он единственный в коллекции users. XElement userXml = documentXml.Element(“users”).Element(“user”); // Последовательно извлекаем данные из документа и заполняем модель пользователя UserInfo.Id = userXml.Element(“id”).Value; UserInfo.Name = userXml.Element(“name”).Value; UserInfo.ScreenName = userXml.Element(“screen_name”).Value; UserInfo.Location = userXml.Element(“location”).Value; UserInfo.Description = userXml.Element(“description”).Value; UserInfo.ProfileImageUrl = userXml.Element(“profile_image_url”).Value; UserInfo.FriendsCount = userXml.Element(“friends_count”).Value; UserInfo.FollowersCount = userXml.Element(“followers_count”).Value; } }; } #endregion

#region GetUserList // Метод возвращает список пользователей // В качестве параметров он принимает тип пользователя - это значение, которое будет // подставляться в строку запроса. Например friends или followers. И коллекцию, которая будет заполнена // данными пользователей. private void GetUserList(string userType, ICollection<User> userList) { // Проверяем, не постой ли Id пользователя if (!string.IsNullOrEmpty(_userId)) { // Загружаем все id подписчиков пользователя Uri userIdUri = new Uri(string.Format(“https://api.twitter.com/1/{0}/ids.xml?user_id={1}”, userType, _userId)); WebClient client = new WebClient(); client.DownloadStringAsync(userIdUri); client.DownloadStringCompleted += (sender, e) => { // Если ошибок не произошло, то загружаем дополнительную информацию для каждого подписчика if (e.Error == null) { // Формируем строку запроса на получение данных пользователей // для того чтобы запросить данные сразу множества пользователей мы перечислим // все id через запятую и передадим их параметру user_id StringBuilder stringBuilder = new StringBuilder(“https://api.twitter.com/1/users/ lookup.xml?user_id=”);

XDocument document = XDocument.Parse(e.Result); XElement ids = document.Element(“id_list”).Element(“ids”);

int count = 0; foreach (XElement id in ids.Elements()) { // проверяем, чтобы было не более 100 id пользователей if (count >= 100) { break; } stringBuilder.Append(string.Format(“{0},”, id.Value)); count++; } // Отправляем сформированный запрос и обрабатываем ответ, заполняя переданную в качестве // параметра коллекцию. client = new WebClient(); u

Page 39: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 39

S ilverlight

client.DownloadStringAsync(new Uri(stringBuilder.ToString().TrimEnd(‘,’))); client.DownloadStringCompleted += (sender1, e1) => { if (e1.Error == null) { XDocument followersXml = XDocument.Parse(e1.Result); foreach (XElement userXml in followersXml.Element(“users”).Elements()) { User user = new User { Id = userXml.Element(“id”).Value, Name = userXml.Element(“name”).Value, ScreenName = userXml.Element(“screen_name”).Value, Location = userXml.Element(“location”).Value, Description = userXml.Element(“description”).Value, ProfileImageUrl = userXml.Element(“profile_image_url”).Value };

userList.Add(user); }

} }; } }; } }

#endregion

#region FollowerList

private ObservableCollection<User> _followerList; public ObservableCollection<User> FollowerList { get { return _followerList; } set { _followerList = value; } }

#endregion

#region FriendList

private ObservableCollection<User> _friendList; public ObservableCollection<User> FriendList { get { return _friendList; } set { _friendList = value; } }

#endregion

#region UserInfo

private User _userInfo; public User UserInfo { get { return _userInfo; } set { _userInfo = value; base.RaisePropertyChanged(“UserInfo”); } }

#endregion }}

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

Для того чтобы получить данные пользователя, нужно вос-пользоваться методом https://api.twitter.com/1/users/lookup, который принимает в качестве параметра список id номеров пользователей, для которых требуется вернуть данные. Например, чтобы получить информацию о пользо-вателе в формате xml, можно воспользоваться следующим запросом: https://api.twitter.com/1/users/lookup.xml? user_id=122334.

Затем создается общий метод GetUserList, который прини-мает в качестве параметров тип пользователя, то есть строку friends или followers, которая будет использоваться в строке запроса, и коллекцию, которая будет заполнена данными пользователей.

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

namespace InfoModule{ public class InfoModule: IModule { private readonly IRegionManager _regionManager; private readonly IUnityContainer _container;

public InfoModule(IRegionManager regionMana- ger, IUnityContainer container) { if (regionManager == null) throw new Excep- tion(“regionManager”); if (container == null) throw new Excepti- on(“container”);

_regionManager = regionManager; _container = container; }

public void Initialize() { _regionManager.RegisterViewWithRegion(“Info- Region”, () => _container.Resolve<Views.In- foView>()); u

Page 40: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 40

S ilverlight

} }}

Разработка модуля отправки твитов

Основной функцией любого Twitter-клиента является отправ-ка коротких сообщений, максимальная длинна которых не превышает 140 символов. В нашем Twitter-клиенте эту функ-цию будет выполнять модуль TwitModule. Добавим в корень проекта три папки Models, ViewModels, Views.

Добавим в папку Views новое представление TwitView. За-тем приведем разметку к следующему виду.

<UserControl x:Class=”TwitModule.Views.TwitView” xmlns=”http://schemas.microsoft.com/winfx/2006/ xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/ xaml”>

<Grid x:Name=”LayoutRoot”> <Grid.RowDefinitions> <RowDefinition Height=”Auto” />

<RowDefinition Height=”*” /> <RowDefinition Height=”*” /> </Grid.RowDefinitions>

<TextBlock Grid.Row=”0” Text=”О чем думаешь?” FontSize=”36” Margin=”0,0,0,6” Foregro- und=”SlateGray” FontWeight=”Bold” />

<TextBox Name=”TwitTextBox” Grid.Row=”1” Height=”100” MaxLength=”140” TextWrapping= ”Wrap” HorizontalAlignment=”Stretch” Accepts- Return=”True” VerticalScrollBarVisibility= ”Auto” />

<Button Command=”{Binding CreateTwitCommand}” CommandParameter=”{Binding ElementName=Twit- TextBox,Path=Text}” Grid.Row=”2” Con- tent=”Твитнуть” Margin=”0,10,0,0” Padding= ”15,5” HorizontalAlignment=”Right” FontSi- ze=”14”/> </Grid></UserControl>

Данная разметка включает в себя текстовое поле для ввода сообщения и кнопку для ее отправки. У кнопки определена команда CreateTwitCommand и параметр, который передает команде текст, введенный пользователем.

Добавим в папку ViewModels модель представления Twit-ViewModel. Отредактируем текст модели представления так, как показано ниже.

namespace TwitModule.ViewModels{ public class TwitViewModel : NotificationObject { private readonly IEventAggregator _eventAggregator; private readonly IRegionManager _regionManager; private readonly string _oauthToken; private readonly string _oauthTokenSecret;

public TwitViewModel(IEventAggregator eventAggregator, IRegionManager regionManager) { if (eventAggregator == null) throw new Exception(“eventAggregator”); if (regionManager == null) throw new Exception(“regionManager”);

_eventAggregator = eventAggregator; _regionManager = regionManager;

CreateTwitCommand = new DelegateCommand<object>(CreateTwit, CanCreateTwit);

IRegion loginRegion = _regionManager.Regions[“LoginRegion”];

if (loginRegion != null) { string[] values = loginRegion.Context.ToString().Split(‘=’, ‘&’); _oauthToken = values[1]; _oauthTokenSecret = values[3];

} }

#region CreateTwitCommand

public DelegateCommand<object> CreateTwitCommand { get; private set; }

private void CreateTwit(object commandArg) { Update(commandArg.ToString()); }

private bool CanCreateTwit(object commandArg) { if (commandArg != null) u

Page 41: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 41

S ilverlight

{ string text = commandArg.ToString(); if (!string.IsNullOrEmpty(text) && text.Length <= 140) { return true; } } return false; }

#endregion

#region Update

private void Update(string text) { OAuthRequest request = new OAuthRequest(); // Ключи полученные при регистрации приложения в Twitter request.ConsumerKey = AppConst.ConsumerKey; request.ConsumerSecret = AppConst.ConsumerSecret; // Для выполнения отправки сообщения в Twitter необходимо использовать POST запрос request.Method = “POST”; request.SignatureMethod = OAuthSignatureMethod.HmacSha1; // В качестве типа запроса нужно указать ProtectedResource “защищенный ресурс” request.Type = OAuthRequestType.ProtectedResource; // Ключи доступа, полученные после авторизации в Twitter request.Token = _oauthToken; request.TokenSecret = _oauthTokenSecret; // Строка запроса для отправки сообщения request.RequestUrl = “https://api.twitter.com/1/statuses/update.xml”; request.Version = “1.0”;

// Создаем словарь для передачи параметра, в данном случае сообщения. // Этот шаг необходим для генерации корректной подписи Dictionary<string, string> requestParams = new Dictionary<string, string>(); requestParams.Add(“status”, text); // Создаем Uri для запроса Uri requestUri = new Uri(request.RequestUrl); // Получаем параметры авторизации string autorizationQuery = request.GetAuthorizationQuery(requestParams);

WebClient client = new WebClient();

client.UploadStringAsync(requestUri, “POST”, autorizationQuery + “&status=” + OAuthTools.UrlEncodeStrict(text)); client.UploadStringCompleted += (sender, e) => { if (e.Error == null) { // Если никаких ошибок не произошло, то передаем текст // сообщения в модуль списка твитов _eventAggregator.GetEvent<CreateTwitEvent>().Publish(e.Result); } }; }

#endregion

#region TwitText

private string _twitText; public string TwitText { get { return _twitText; } set { _twitText = value; base.RaisePropertyChanged(“TwitText”); } }

#endregion }} u

Page 42: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 42

S ilverlight

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

Метод GetAuthorizationQuery экземпляра класса OAuth-Request принимает в качестве параметра словарь, содержа-щий список пар ключ\значение, где в качестве ключа указыва-ется название параметра для запроса, а в качестве значения его содержимое. Например, в данном случае мы отправляем всего один обязательный параметр – status. Status – это текст сообщения, которое будет отображаться в списке тви-тов.

Чтобы опубликовать сообщение в Twitter, необходимо выпол-нить следующий запрос https://api.twitter.com/1/sta-tuses/update.xml?status=”some text”. Где some text – это текст публикуемого сообщения.

Чтобы сообщение было успешно отправлено, необходимо выполнить html-кодировку. Сделать это можно с помощью статического метода UrlEncodeStrict класса OAuthTools.

Завершающим шагом мы передаем только что опубликован-ное сообщение модулю TwitListModule. Для этого мы пу-бликуем ответ для события CreateTwitEvent. Подписку на это событие мы позже реализуем в модуле TwitListModule.

Зарегистрируем наш модуль. Для этого добавим класс TwitModule в корень проекта TwitModule. Как вы заметили, класс и проект называются одинаково, это сделано для удоб-ства. Ниже приведен листинг класса TwitModule.

using System;

using Microsoft.Practices.Prism.Modularity;using Microsoft.Practices.Prism.Regions;

namespace TwitModule{ public class TwitModule : IModule { private readonly IRegionManager _regionManager;

public TwitModule(IRegionManager regionManager) { if (regionManager == null) throw new Excep- tion(“regionManager”);

_regionManager = regionManager; }

public void Initialize() { _regionManager.RegisterViewWithRegion(“Twit- Region”, typeof(Views.TwitView)); } }}

Разработка модуля списка твитов

В нашем Twitter-клиенте будет присутствовать возможность просмотра 20 последних твитов и упоминаний. Для этого мы реализуем в модуле TwitListModule представление Twit-ListView, которое будет включать в себя две вкладки. На первой будет располагаться список из 20-ти последних тви-тов, а на второй список упоминаний.

Ниже приведена разметка представления TwitListView.

<UserControl xmlns:sdk=”http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk” x:Class=”TwitListModule.Views.TwitListView” xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”>

<Grid x:Name=”LayoutRoot”> <Grid.RowDefinitions> <RowDefinition Height=”Auto” /> <RowDefinition Height=”*” /> </Grid.RowDefinitions> <sdk:TabControl Grid.Row=”1” HorizontalAlignment=”Stretch” VerticalAlignment=”Stretch”> <sdk:TabItem Header=”Лента”> <ListBox ItemsSource=”{Binding TimelineList, Mode=TwoWay}” HorizontalAlignment=”Stretch” VerticalAlignment=”Stretch”> <ListBox.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width=”Auto” /> <ColumnDefinition Width=”*” /> </Grid.ColumnDefinitions> <Image Grid.Column=”0” Source=”{Binding Path=User.ProfileImageUrl}” Margin=”4”/> <StackPanel Grid.Column=”1” Orientation=”Vertical” Margin=”4”> <StackPanel Orientation=”Horizontal” > <TextBlock Text=”{Binding Path=User.ScreenName}” Margin=”0,0,4,0” FontWeight=”Bold” /> <TextBlock Text=”{Binding Path=User.Name}” /> </StackPanel> <TextBlock Text=”{Binding Path=Text}” /> <TextBlock Text=”{Binding Path=CreatedAt}” /> </StackPanel> </Grid> </DataTemplate> </ListBox.ItemTemplate> </ListBox> u

Page 43: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 43

S ilverlight

</sdk:TabItem> <sdk:TabItem Header=”Упоминания”> <ListBox ItemsSource=”{Binding MentionList, Mode=TwoWay}” HorizontalAlignment=”Stretch” VerticalAlignment=”Stretch”> <ListBox.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width=”Auto” /> <ColumnDefinition Width=”*” /> </Grid.ColumnDefinitions> <Image Grid.Column=”0” Source=”{Binding Path=User.ProfileImageUrl}” Margin=”4”/> <StackPanel Grid.Column=”1” Orientation=”Vertical” Margin=”4”> <StackPanel Orientation=”Horizontal” > <TextBlock Text=”{Binding Path=User.ScreenName}” Margin=”0,0,4,0” FontWeight=”Bold” /> <TextBlock Text=”{Binding Path=User.Name}” /> </StackPanel> <TextBlock Text=”{Binding Path=Text}” /> <TextBlock Text=”{Binding Path=CreatedAt}” /> </StackPanel> </Grid> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </sdk:TabItem> </sdk:TabControl> </Grid></UserControl>

Создадим в папке ViewModels новый класс и назовем его TwitListViewModel. Отредактируем модель представления, так как показано ниже.

namespace TwitListModule.ViewModels{ public class TwitListViewModel : NotificationObject { private readonly IUnityContainer _container; private readonly IRegionManager _regionManager; private readonly IEventAggregator _eventAggregator; private readonly string _oauthToken; private readonly string _oauthTokenSecret;

public TwitListViewModel(IUnityContainer container, IRegionManager regionManager, IEventAggregator eventAggregator) { if (container == null) throw new ArgumentNullException(“container”); if (regionManager == null) throw new ArgumentNullException(“regionManager”); if (eventAggregator == null) throw new ArgumentNullException(“eventAggregator”);

_container = container; _regionManager = regionManager; _eventAggregator = eventAggregator;

IRegion loginRegion = _regionManager.Regions[“LoginRegion”];

if (loginRegion != null) { // Получаем ключи доступа string[] values = loginRegion.Context.ToString().Split(‘=’, ‘&’); _oauthToken = values[1]; _oauthTokenSecret = values[3];

} // Инициализация коллекций TimelineList - хранит список твитов, MentionList - список упоминаний TimelineList = new ObservableCollection<Status>(); MentionList = new ObservableCollection<Status>();

// Подписываемся на событие публикации нового твита. _eventAggregator.GetEvent<CreateTwitEvent>().Subscribe(CreateTwit, ThreadOption.UIThread, true);

// Получаем последние 20 тивитов GetHomeTimeline(); // Получаем последние 20 упоминаний GetMentions(); } u

Page 44: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 44

S ilverlight

// Метод загрузки твитов #region GetHomeTimeline

public void GetHomeTimeline() { // Формируем строку запроса для авторизации OAuthRequest request = new OAuthRequest(); request.ConsumerKey = AppConst.ConsumerKey; request.ConsumerSecret = AppConst.ConsumerSecret; request.Method = “GET”; request.SignatureMethod = OAuthSignatureMethod.HmacSha1; request.Type = OAuthRequestType.ProtectedResource; request.Token = _oauthToken; request.TokenSecret = _oauthTokenSecret; request.RequestUrl = “https://api.twitter.com/1/statuses/home_timeline.xml”; request.Version = “1.0”;

string s = request.RequestUrl + “?” + request.GetAuthorizationQuery();

// Отправляем запрос WebClient client = new WebClient(); client.DownloadStringAsync(new Uri(s)); client.DownloadStringCompleted += (sender, e) => { if (e.Error == null) { TimelineList.Clear(); XDocument documentXml = XDocument.Parse(e.Result); // Заполняем список твитов foreach (XElement statusXml in documentXml.Element(“statuses”).Elements()) { Status status = new Status(); status.Id = statusXml.Element(“id”).Value; status.Text = statusXml.Element(“text”).Value; status.User = new User(); status.User.Id = statusXml.Element(“user”).Element(“id”).Value; status.User.Name = statusXml.Element(“user”).Element(“name”).Value; status.User.ScreenName = statusXml.Element(“user”).Element(“screen_name”).Value; status.User.Location = statusXml.Element(“user”).Element(“location”).Value; status.User.Description = statusXml.Element(“user”).Element(“description”).Value; status.User.ProfileImageUrl = statusXml.Element(“user”).Element(“profile_image_url”).Value; status.User.FriendsCount = statusXml.Element(“user”).Element(“friends_count”).Value; status.User.FollowersCount = statusXml.Element(“user”).Element(“followers_count”).Value;

TimelineList.Add(status); } } }; }

#endregion

#region GetMentions

private void GetMentions() { // Формируем строку запроса для авторизации OAuthRequest request = new OAuthRequest(); request.ConsumerKey = AppConst.ConsumerKey; request.ConsumerSecret = AppConst.ConsumerSecret; request.Method = “GET”; request.SignatureMethod = OAuthSignatureMethod.HmacSha1; request.Type = OAuthRequestType.ProtectedResource; request.Token = _oauthToken; request.TokenSecret = _oauthTokenSecret; request.RequestUrl = “https://api.twitter.com/1/statuses/mentions.xml”; request.Version = “1.0”;

string s = request.RequestUrl + “?” + request.GetAuthorizationQuery(); // Отправляем запрос WebClient client = new WebClient(); client.DownloadStringAsync(new Uri(s)); u

Page 45: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 45

S ilverlight

client.DownloadStringCompleted += (sender, e) => { if (e.Error == null) { XDocument documentXml = XDocument.Parse(e.Result); // Заполняем список упоминаний foreach (XElement statusXml in documentXml.Element(“statuses”).Elements()) { Status status = new Status(); status.Id = statusXml.Element(“id”).Value; status.Text = statusXml.Element(“text”).Value; status.User = new User(); status.User.Id = statusXml.Element(“user”).Element(“id”).Value; status.User.Name = statusXml.Element(“user”).Element(“name”).Value; status.User.ScreenName = statusXml.Element(“user”).Element(“screen_name”).Value; status.User.Location = statusXml.Element(“user”).Element(“location”).Value; status.User.Description = statusXml.Element(“user”).Element(“description”).Value; status.User.ProfileImageUrl = statusXml.Element(“user”).Element(“profile_image_url”).Value; status.User.FriendsCount = statusXml.Element(“user”).Element(“friends_count”).Value; status.User.FollowersCount = statusXml.Element(“user”).Element(“followers_count”).Value;

MentionList.Add(status); } } }; } // добавляет только что созданный твит в список #endregion

#region CreateTwit

private void CreateTwit(string p) { XDocument documentXml = XDocument.Parse(p); XElement statusXml = documentXml.Element(“status”);

Status status = new Status(); status.Id = statusXml.Element(“id”).Value; status.Text = statusXml.Element(“text”).Value; status.User = new User(); status.User.Id = statusXml.Element(“user”).Element(“id”).Value; status.User.Name = statusXml.Element(“user”).Element(“name”).Value; status.User.ScreenName = statusXml.Element(“user”).Element(“screen_name”).Value; status.User.Location = statusXml.Element(“user”).Element(“location”).Value; status.User.Description = statusXml.Element(“user”).Element(“description”).Value; status.User.ProfileImageUrl = statusXml.Element(“user”).Element(“profile_image_url”).Value; status.User.FriendsCount = statusXml.Element(“user”).Element(“friends_count”).Value; status.User.FollowersCount = statusXml.Element(“user”).Element(“followers_count”).Value;

TimelineList.Insert(0, status); }

#endregion

#region TimelineList

private ObservableCollection<Status> _timelineList; public ObservableCollection<Status> TimelineList { get { return _timelineList; } set { _timelineList = value; } }

#endregion

#region MentionList

private ObservableCollection<Status> _mentionList; public ObservableCollection<Status> MentionList { u

Page 46: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 46

S ilverlight

get { return _mentionList; } set { _mentionList = value; } }

#endregion

}}

В конструкторе модели представления мы подписываемся на событие CreateTwitEvent, которое использует в качестве обработчика метод CreateTwit. Это работает следующим образом.

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

Этот xml ответ в виде строки публикуется для события Cre-ateTwitEvent. Модель представления TwitListViewModel содержит подписку на это событие и после публикации со-общения выполняет метод CreateTwit, передав ему в каче-стве параметра xml с данными опубликованного сообщения и данными пользователя.

Для загрузки 20 последних сообщений выполняется метод https://api.twitter.com/1/statuses/home_timeline.xml. В качестве дополнительных параметров этому методу можно передать следующие значения:

{ Сount – количество возвращаемых записей;

{ Since_id – возвращает записи с id большим, чем указан-но в параметре;

{ Max_id – возвращает записи с id меньшим указанного;

{ Page – номер страницы результатов.

Это краткий список параметров, которые можно передать в запросе. Более подробное описание этого и других методов можно получить на официальном сайте Twitter API.

Работа метода mentions.format аналогична home_timeli-ne.format.

Добавим в корень проекта TwitListModule класс TwitList-Module и приведем его к следующему виду.

using System;using Microsoft.Practices.Prism.Modularity;using Microsoft.Practices.Prism.Regions;using Microsoft.Practices.Unity;

namespace TwitListModule{ public class TwitListModule: IModule { private readonly IRegionManager _regionManager; private readonly IUnityContainer _container;

public TwitListModule(IRegionManager regionMa- nager, IUnityContainer container) { if (regionManager == null) throw new Excep- tion(“regionManager”);

_regionManager = regionManager; _container = container; }

public void Initialize() { _regionManager.RegisterViewWithRegion(“Twit- ListRegion”, () => _container.Resolve<Views. TwitListView>()); }

}}

Готовое приложение

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

Использование готовых библиотек для работы с Twitter

Альтернативой работы с REST API является использование сторонних библиотек, которые существенно упрощают про-цесс разработки. Одной из таких библиотек является Tweet-Sharp.

Добавить ее можно следующей командой:

PM> Install-Package TweetSharp.

Чтобы продемонстрировать работу с библиотекой TweetShrp, изменим в нашем приложении код, отвечающий за работу с Twitter, то есть там, где сейчас напрямую используется REST API, мы будем использовать TweetSharp.

Откроем модель представления TwitViewModel в проекте TwitModule и изменим код метода Update() следующим об-разом.

public void Update(string text){ // генерируем заголовок для авторизации service.AuthenticateWith(_oauthToken, _oauthTo- kenSecret); // отправляем твит service.SendTweet(text, (tstatus, trespounce) => { // используем лямбда выражение для обра- ботки ответа if (trespounce.InnerException == null) { _eventAggregator.GetEvent<CreateTwit- Event>().Publish(tstatus); } });} u

Page 47: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 47

S ilverlight

Добавим переменную Service типа TwitterService.

private TwitterService service;

Затем инициализируем ее в конструкторе TwitViewModel.

service = new TwitterService(AppConst.ConsumerKey, AppConst.ConsumerSecret);

Изменим тип события CreateTwitEvent на TwitterStatus. Для этого добавим TweetSharp пакет в библиотеку классов Infrastructure.

Перейдем к списку твитов. Аналогичным образом объявим и инициализируем переменную service типа TwitterService.

Добавим следующий код в конструктор.

service = new TwitterService(AppConst.ConsumerKey, AppConst.ConsumerSecret);

service.AuthenticateWith(_oauthToken, _oauthToken-Secret);

А так же изменим тип коллекций TimeLineList и MentionList на TwitterStatus.

Ниже приведен обновленный листинг с кодом метода Get-HomeTimeline().

public void GetHomeTimeline(){ // Загружаем двадцать последних твитов service.ListTweetsOnHomeTimeline(20,(twitterSta- tuses, response)=> { // Используем диспетчер, чтобы обратиться к // основному потоку и заполнить коллекцию // твитов. Если попробовать обратиться к // коллекции TimelineList не через диспет- // чер, то получим ошибку межпотокового // доступа dispatcher.BeginInvoke(() => { // Заполняем коллекцию твитами foreach (TwitterStatus twitterStatus in twitterStatuses) { TimelineList.Add(twitterStatus); } }); });}

Код метода GetMentions() аналогичен методу GetHomeTi-meline(), только вместо метода загрузки твитов, загружают-ся упоминания.

private void GetMentions(){ service.ListTweetsMentioningMe((twitterStatuses, response) => { dispatcher.BeginInvoke(() => { foreach (TwitterStatus twitterStatus in twitterStatuses) { MentionList.Add(twitterStatus); } }); });}

Объявим глобальную переменную уровня класса типа Dispatcher и инициализируем ее следующим образом.

dispatcher = Application.Current.RootVisual.Dispat-cher;

Единственное, что осталось сделать – это изменить метод

CreateTwit. Приведем метод CreateTwit к следующему виду.

private void CreateTwit(TwitterStatus twitterStatus){ TimelineList.Insert(0, twitterStatus);}

Как видите, используя TweetSharp, мы существенно сокра-тили код, требующийся написать. Всю работу на себя взяла библиотека, мы лишь вызываем ее методы.

Естественно, TweetSharp не единственная библиотека, ко-торая работает на Silverlight. Существует немало библиотек, предоставляющих обширные возможности для работы с Twitter. На мой взгляд, наиболее интересной среди прочих яв-ляется LinqToTwitter. Ниже приведен пример получения спи-ска твитов с использованием библиотеки LinqToTwitter.

TwitterContext twitterCtx = new TwitterContext();

IQueryable<Status> twitters = from tweet in twitterCtx.Status where tweet.Type == StatusType.Home && tweet.Page == 2 select tweet;foreach (Status statuse in twitters){ // Какой-то код}

Отправка изображений

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

TwitPic

Начнем, пожалуй, с хостинга изображений twitpic. Перед тем как приступить к написанию кода, необходимо зарегистриро-вать новое приложение на twitpic. Для этого перейдем на сайт http://dev.twitpic.com/apps/new/ и добавим новое приложение. Если приложение было успешно создано, система перена-правит нас на страницу http://dev.twitpic.com/apps/ где пред-ставлен список приложений. Нас интересует атрибут Api key.u

Page 48: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 48

S ilverlight

Для работы нам потребуется библиотека OAuth fro .NET и Ham- mock. Ниже приведен код, публикации изображения в twitpic.

OAuthRequest oAuth = new OAuthRequest();// Ключи, полученные при регистрации приложения в TwitteroAuth.ConsumerKey = «V9lsOoclYGV6JAht0CPBQ»;oAuth.ConsumerSecret = «zj0EPiMhpJUKYQtg4v649f0HSHAONU9Ly4PTwVIY3A0»;// Для выполнения отправки сообщения в Twitter необходимо использовать POST запросoAuth.Method = «GET»;oAuth.SignatureMethod = OAuthSignatureMethod.HmacSha1;// В качестве типа запроса нужно указать ProtectedResource “защищенный ресурс”oAuth.Type = OAuthRequestType.ProtectedResource;// Ключи доступа, полученные после авторизации в TwitteroAuth.Token = access.Token;oAuth.TokenSecret = access.TokenSecret;// Строка запроса для отправки сообщенияoAuth.RequestUrl = «https://api.twitter.com/1/account/verify_credentials.xml»;oAuth.Version = «1.0»;

// Предполагается использование OpenFileDialogFileInfo f = new FileInfo(@«C:\Users\Валерий\Pictures\С проигрывателя ValeraWP\Альбом камеры\WP_000025.jpg»);

// Подготавливаем запросRestRequest request = new RestRequest();// Адрес для публикации изображенияrequest.Path = «http://api.twitpic.com/2/upload.xml»;// Заголовок авторизацииrequest.AddHeader(«X-Verify-Credentials-Authoriza-tion», oAuth.GetAuthorizationHeader());// Ключ, полученный после регистрации приложения в twitpicrequest.AddField(«key», «1f3721432a83aa54e0c6d1af08 de1611»);// Сообщениеrequest.AddField(«message», «Привет TwitPic»);// Изображениеrequest.AddFile(«media», «WP_000025.jpg», f.Open-Read(), «image/jpeg»);

// Отправляем запрос с помощью HammockRestClient client = new RestClient();client.BeginRequest(request);

Photobucket

Существует более удобный способ публикации изображений, используя метод statuses/update_with_media, предостав-ляемый Twitter API.

Обратите внимание, что при использовании https://upload.- twitter.com, текст сообщения и изображение не участвуют в формировании подписи для авторизации.

OAuthRequest oAuth = new OAuthRequest();// Ключи, полученные при регистрации приложения в Twitter

oAuth.ConsumerKey = «V9lsOoclYGV6JAht0CPBQ»;oAuth.ConsumerSecret = «zj0EPiMhpJUKYQtg4v649f0HSHAONU9Ly4PTwVIY3A0»;// Для выполнения отправки сообщения в Twitter необходимо использовать POST запросoAuth.Method = «POST»;oAuth.SignatureMethod = OAuthSignatureMethod.HmacSha1;// В качестве типа запроса нужно указать ProtectedResource “защищенный ресурс”oAuth.Type = OAuthRequestType.ProtectedResource;// Ключи доступа, полученные после авторизации в TwitteroAuth.Token = access.Token;oAuth.TokenSecret = access.TokenSecret;// Строка запроса для отправки сообщенияoAuth.RequestUrl = «https://upload.twitter.com/1/statuses/update_with_media.xml»;oAuth.Version = «1.0»;

// Предполагается использование OpenFileDialogFileInfo f = new FileInfo(@»C:\Users\Валерий\Pictures\С проигрывателя ValeraWP\Альбом камеры\WP_000025.jpg»);

RestRequest request = new RestRequest();request.Path = «https://upload.twitter.com/1/statuses/update_with_media.xml»;request.AddHeader(«Authorization», oAuth.GetAuthorizationHeader());request.AddField(«status», «Привет Photobucket»);request.AddFile(«media[]», «WP_000025.jpg», f.OpenRead(), «image/jpeg»);

// Отправляем запрос с помощью HammockRestClient client = new RestClient();client.BeginRequest(request);

Если вы планируете использовать библиотеки для работы с Twitter, например LinqToTwitter, то отправку медиа контента можно упростить. Ниже приведен пример публикации изо-бражения с использованием LinqToTwitter.

TwitterContext = new TwitterContext();

FileInfo f = new FileInfo(@«C:\Users\Валерий\Pictures\С проигрывателя ValeraWP\Альбом камеры\WP_000025.jpg»);byte[] b = new byte[f.Length];f.OpenRead().Read(b, 0, b.Length);

List<Media> mediae = new List<Media>();

mediae.Add(new Media{ContentType = MediaContentType.JPEG ,Data = b,FileName = «WP_000025.jpg»});

twitterCtx.TweetWithMedia(«Привет!», true, mediae);

Для работы с REST службами и Твиттером существует огром-ное количество библиотек, реализованных сообществом раз-работчиков. Какие-то работают хорошо, какие-то не очень. Многие библиотеки с открытым исходным кодом мне прихо-дилось «допиливать» вручную, чтобы устранить некоторые ошибки. Для себя я так и не нашел библиотеку для работы с Twitter, которая всем меня устраивает, поэтому я принял решение использовать гибридный подход, то есть взять за основу хорошо отлаженный механизм и реализовать на его основе свою библиотеку. n

Page 49: 03 (07) 2012 MSDeveloperRU

Найди себе заказчика с помощью

Microsoft помогает найти заказчика

Для того чтобы попасть в каталог профессиональных разработчиков, необходимо зарегистрироваться на сайте http://webprofessionals.ru или http://appprofessionals.ru.

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

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

Рекл

ама

Page 50: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 50

И нтервью

Беседовал Станислав Горнаков

Интервью сПавлом Чебунинымруководителем пресс-службы компании ISPserver.com

Станислав Горнаков: Павел, добрый день! Компания ISPserver несколько лет назад запустила услугу – облачный хостинг. Ваша компания была одной из первых, кто это сделал на нашем рынке. Расскажите немного, что представляет собой облач-ный хостинг от ISPserver.

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

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

А какие еще очевидные преимущества у облачного хостинга перед традицион-ными видами хостинга?

Зарубежный рынок изобилует пред-ложениями, реализованными по кон-цепции облачных вычислений (cloud computing), ведутся активные диалоги в хостинг-сообществе. Почему? Потому что это, прежде всего, выгодно клиен-ту. Традиционный виртуальный хостинг предполагает, что на одном физиче-ском сервере размещено несколько веб-проектов разных клиентов, кото-рые в свою очередь делят между собой ресурсы сервера. Данный вид хостин-га приемлем для большинства сайтов

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

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

А за счет чего достигается надежность и отказоустой-чивость облачного хостинга?

За счет того, что архитектура облачного хостинга распределена между несколь-кими физическими серверами с приме-

нением отказоустойчивых кластерных технологий. В качестве платформы облачных вычислений мы используем комплекс программного обеспечения ISPmanager Cluster.

Павел, расскажите подроб-нее о платформе облачных вычислений ISPmanager Cluster.

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

Кроме того, веб-интерфейс ISPmanager Cluster спроектирован на основе попу-лярной панели управления ISPmanager Pro, поэтому он очень удобен и привы-чен.

Павел, а если я только соз-дал свой сайт, он еще нигде не «раскручен», то нужно ли мне платить за такой сайт, который по сути пока про-стаивает? u

?

??

?

?

Page 51: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 51

И нтервью

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

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

Все это звучит впечатляюще, сразу захотелось попробо-вать…

Нет ничего проще. Наш облачный хо-стинг можно попробовать бесплатно в течение 5 тестовых дней и самостоя-тельно оценить для себя все его пре-имущества.

А скажите, Павел, какие услуги еще предоставляет компания ISPserver? Как дав-но работает на рынке?

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

Сейчас мы предоставляем услуги хо-стинга по всему миру. Дата-центры, в которых размещено наше собственное оборудование, расположены на терри-тории РФ, США и Европы. В свое вре-мя компания ISPserver стояла у исто-ков возникновения в России тогда еще нового веяния в области хостинга – технологии виртуальных выделенных серверов (VDS/VPS). На западе этот вид хостинга называют VPS. Мы же изначально стали именовать данный вид хостинга VDS и в России вошла в обиход именно эта аббревиатура. На текущий момент, мы предоставляем традиционный перечень услуг хостинг-провайдера.

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

Ну, и, безусловно, нашим «коньком» всегда была и остается круглосуточная многоязыковая служба технической поддержки. Любой наш клиент из лю-бой точки мира и в любое время может обратиться за помощью и в оператив-ном режиме получить исчерпывающий ответ.

Расскажите немного о своих клиентах. На кого вы, пре-жде всего, ориентированы?

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

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

Многие хостинг-провайдеры практикуют партнерские программы, предусмотрены ли они у вас?

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

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

Павел, расскажите, а что в планах?

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

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

Павел, спасибо за интервью, желаю компании ISPserver реализации намеченных планов. n

Распределение ролей в ISPmanager Cluster

?

??

?

?

?

Page 52: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 52

Р азработка

Сообщения с таймеромАвторАндрей Гордиенков[email protected]://softblog.violet-tape.ru/г. Москва

При работе со многими программами мы не обращаем внимание на множество вещей в интерфейсе, считая это само собой разумеющимся, или же считаем милой

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

Задумка

Если подумать, то все вспомнят о статусной строке в при-ложении, где часто пишется состояние программы, уведом-ление о завершении каких-либо фоновых задач, или другая интересная информация о работе программы. Еще можно вспомнить о программах, которые показывают информаци-онное сообщение пользователю в каком-либо специальном месте интерфейса, а через какое-то время (секунд 5) надпись исчезает. Учитывая последние тенденции к тому, чтобы из-бавлять пользователя от popup-окон, в которых написано что-то в духе: «Данная операция не может быть совершена, так как она в процессе выполнения», и на всплывшем окне толь-ко одна кнопка OK. Раздражает такое поведение неимоверно, так как приводит к лишним действиям! В общем, сегодня я покажу, как можно реализовать набор классов для реализа-ции такого поведения и использовать его в дальнейшем без существенных модификаций.

Неискушенный читатель наверно может воскликнуть: «Что за бредятина, какие еще наборы классов для того, чтобы сде-лать два set’a строки? Если надо показать сообщение, так присвой переменной сообщения нужный текст, когда не надо – присвой пустую строку. Any problem?».

Если кратко, то проблем много! Сейчас попробую перечис-лить их:

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

{ Надо запоминать предыдущий текст в сообщении, если он был.

{ Легко запутаться что, где и зачем реализовано. Скорее всего, будет много копи-пастов, и, следовательно, больше мест для ошибок.

{ Некрасиво!

Лично для меня хватило только первого пункта из-за моей профессиональной лени.

Подготовка

Демонстрационный проект будет на базе WPF с использова-нием Rx. О да, мне очень понравился Rx ‒ он идеально под-ходит для нашей цели в силу своей компактности при записи и общем удобстве использования.

Честно скажу, я сразу сделал проект на Rx, и хотя была мысль сделать то же самое без использования этого фреймворка, но ужаснувшись дебрям кода который надо будет написать, я решил так не делать. Мне кажется, можно будет и так оценить краткость решения.

Итак, у нас будет настольное приложение на WPF. Для того чтобы не заморачиваться с INotifyPropertyChanged я приме-няю Kind of Magic, и так как его использование было описано ранее, то подробно останавливаться на этом не буду.

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

Визуально, наше приложение будет выглядеть так:

Я думаю, функции приложения ясны из подписей к кнопкам. Xaml интереса не представляет, поэтому его рассматривать не будем. Из установленных NuGet пакетов:

{ Rx-Main{ Rx-WPF.

Устанавливать можно только последний, так как он автома-том подтянет и поставит основную сборку. По организации взаимодействия интерфейса и всего остального – использу-ем MVVM.

Еще раз четко проговорим, какие задачи должны быть реше-ны:

{ Возможность установки постоянного информационного сообщения.

{ Возможность установки временного информационного со-общения на заданный промежуток времени.

{ После завершения показа временного сообщения, авто-матически, без нашего участия, показывается постоянное сообщение, если нет других временных сообщений, срок жизни которых еще не истек. u

Page 53: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 53

Р азработка

{ Любое новое постоянное сообщение не прерывает показ временного сообщения.

{ Любое временное сообщение показывается сразу же.

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

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

public class StatusMessageManager { private readonly Stack<TemporaryMessage> timerMessages = new Stack<TemporaryMessage>(); private string constMessage; private class TemporaryMessage : IDisposable { public void Dispose() { } }}

Класс сообщений

Остановимся поподробнее на классе сообщения. Он должен знать как минимум:

{ Текст { Время жизни в секундах{ Закончилось ли время жизни.

Вообще, один класс можно использовать как для временных, так и для постоянных сообщений. Для постоянных сообще-ний мы не будем запускать таймер, и оно всегда будет «жи-вым», актуальным.

Так же класс должен уметь отсчитывать время и сообщать об истечении этого времени. Для этого используем Timer из про-странства System.Timers (другие не очень подойдут).

private class TemporaryMessage : IDisposable { private readonly Timer timer = new Timer(); private readonly int lifeTime; private Action<TemporaryMessage> expired;

public string Message { get; private set; } public bool IsExpired { get; private set; }

public void Dispose() { expired = null; timer.Dispose(); }

}

Сообщение создается один раз и не модифицируется в те-чение жизни, так что все параметры задаем в конструкторе.

public TemporaryMessage(string message, int life-Time, Action<TemporaryMessage> expired) { this.lifeTime = lifeTime; this.expired = expired;

Message = message; IsExpired = false;

if (lifeTime > 0) { timer.Interval = this.lifeTime*1000; timer.Elapsed += (sender, args) => Elapsed(); timer.Start(); }}

private void Elapsed() { timer.Stop();

IsExpired = true; expired(this);}

В реализации видно, что для временных сообщений мы за-пускаем таймер, по срабатыванию которого, останавливаем таймер, обозначаем сообщение как «умершее» и уведомля-ем об этом управляющий класс StatusMessageManager.

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

Класс управления сообщениями

Управлять публикацией сообщений будем с помощью Rx. Ос-новными методами класса являются:

{ Выставление потока сообщений,{ Установка новых сообщений.{ Начнем с выставления потока сообщений.

При работе с Rx, важно для себя понять, что это работа с потоком данных, а не со статиче-ским набором данных.

private readonly BehaviorSubject<string> subject = new BehaviorSubject<string>(“”);

public IObservable<string> MessageStream() { return subject;}

Используем BehaviorSubject, он запоминает только послед-нее свое значение, чего нам будет достаточно. Далее я по-кажу, как мы будем использовать этот метод для подписки на новые сообщения. Мне кажется, идеологически более верно представить это методом, нежели свойством, в виду «долго-срочности» его работы. Есть такое ощущение.

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

public void SetMessage(string message, int freeze-Time = 0) { if (freezeTime < 0) freezeTime = 0;

if (timerMessages.Count == 0) { subject.OnNext(message); } if (freezeTime == 0) { constMessage = message; } recentMessage = new TemporaryMessage(message, freezeTime, CheckNextMessage);

if (freezeTime > 0) { timerMessages.Push(recentMessage); subject.OnNext(message); }}

Если нет временных сообщений, то сразу публикуем новое значение в потоке subject. Сохранение последнего постоян-ного сообщения будет нужно далее. u

Page 54: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 54

Р азработка

Важный момент: в качестве метода для отра-ботки по срабатыванию таймера идет проверка наличия следующего сообщения.

Сейчас мы этот метод и рассмотрим CheckNextMessage.

private void CheckNextMessage(TemporaryMessage expi-redMessage) { TemporaryMessage message = null;

if (timerMessages.Count == 0) { subject.OnNext(constMessage); return; } if (expiredMessage != timerMessages.Peek()) { return; } while (timerMessages.Count > 0) { message = timerMessages.Peek(); if (!message.IsExpired) break; timerMessages.Pop(); } subject.OnNext(message == null || message.IsExpired ? constMessage : message.Message);}

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

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

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

Использование

Все использование и красота при желании остается во ViewModel, хотя конечно можно фантазировать. Итак, у нас есть StatusMessageManager, который можно использовать во вьюмодели. Не буду на вьюмодели подробно останавливать-ся, рассмотрим только самые интересные места.

Итак, объявление и подписка на появление новых сообщений от управляющего класса. Подписываться будем в конструкто-ре. Обратите внимание, что

подписка на поток событий идет для потока GUI, с помощью метода ObserveOnDispatcher.

public NotificationViewModel() { // some code was skipped

statusMessageManager = new StatusMessageManager();

statusMessageManager.MessageStream() .ObserveOnDispatcher() .Subscribe(SetMessage);}private void SetMessage(string message) { InfoMessage = message;}

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

private void SetStatusMessage(string message) { statusMessageManager.SetMessage(message);}

private void SetStatusMessageFreeze(string message, int freezeTime) { statusMessageManager.SetMessage(message, freezeTime);}

Как я уже сказал, при работе с Rx, стоит мыслить о его ис-пользовании как о непрерывном потоке данных. С помощью одного метода мы помещаем данные в поток, там они каким-либо образом обрабатываются (задерживаются, агрегиру-ются, суммируются и так далее) и помощью другого метода принимаем результат. Может быть сначала непривычно, но стоит чуть поэкспериментировать и все встает на свои места, и становится понятно. Работать с Rx легче чем с событиями (event), компактнее.

И теперь как это использовать, например, при нажатии на кнопки о важных сообщениях на 2 и 6 секунд:

private void OnShortNotification() { SetStatusMessageFreeze(“Attention for 2 sec!”, 2);}

private void OnLongerNotification() { SetStatusMessageFreeze(“Attention for 6 sec!”, 6);}

Ну не красота ли?! В программе попробуйте запустить долгий процесс и вызвать сообщение на 2 секунды. Или вызвать со-общение на 6 секунд, а потом на 2 и посмотреть, как меняют-ся сообщения, как ведут себя классы.

Я думаю, что использование класса StatusMessageManager предельно простое и цена внедрения в проект низка.

Развитие

Можно развить функционал класса, сделав постоянные со-общения в некотором роде тоже слоями, с метками жизни.

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

{ Готово{ Загрузка абонентов…{ Загрузка товаров…{ Загрузка складов… (быстрее заканчивается загрузка то-

варов и приходит код отмены, затем заканчивается загруз-ка складов)

{ Загрузка абонентов… { Готово.

Или еще можно получать GUID и для временных записей, чтобы продлевать их жизнь, если они до сих пор живы. Такой сценарий может быть использован для сервисов, которые должны регулярно посылать ответы и по этому ответу прод-левать временное сообщение. Например, для индикации ра-боты процесса, в ходе которого нельзя оценить его прогресс и предсказать время окончания работы.

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

Source code

Page 55: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 55

Б езопасность

Беспроводные сети: защита и нападение

АвторНикита Львов [email protected]://mgupi-it.ruMSP, MCTSКомпания: МГУПИг. Москва

Наверно все читатели знакомы с термином Wi-Fi, который обозна-чает беспроводные сети стандар-

та 802.11. Стандарт IEEE 802.11 явля- ется общепринятым стандартом постро- ения беспроводных сетей ‒ это набор стандартов связи, для коммуникации в беспроводной локальной сетевой зоне частотных диапазонов 2,4; 3,6 и 5 ГГц.

За счет специфики среды передачи данных, которой является радиоэфир, остро встает вопрос безопасно-сти в беспроводных сетях.

Шифрование WEP

Теория

Wired Equivalent Privacy (WEP) ‒ алго-ритм для обеспечения безопасности сетей Wi-Fi. Предназначен для обеспе-чения конфиденциальности и защиты передаваемых по сети данных от неав-торизованного прослушивания. Осно- вой WEP является поточный шифр RC4, в качестве средства проверки целост-ности передаваемых данных путем вы-числения контрольной суммы исполь-зуется алгоритм CRC32.

Кадр данных WEP состоит из двух ча-

стей: зашифрованной и незашифрован-ной.

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

1. Контрольная сумма от поля «дан-ные» вычисляется по алгоритму CRC32 и добавляется в конец ка-дра.

2. Данные с контрольной суммой шиф-руются алгоритмом RC4, использу-ющим в качестве ключа сид.

3. Проводится операция XOR (инвер-сия эквиваленции) над исходным текстом и шифротекстом.

4. В начало кадра добавляется вектор инициализации и идентификатор ключа.

Декапсуляция данных при получении кадра происходит по следующему ал-горитму:

1. К используемому ключу добавляет-ся вектор инициализации.

2. Происходит расшифрование с клю-чом, равным сиду.

3. Проводится операция XOR над по-лученным текстом и шифротекстом.

4. Проверяется контрольная сумма.

Нападение

В начало каждого кадра данных зано-сится вектор инициализации, в то же время ключом шифрования для каждо-го пакета является сид, который пред-ставляет собой вектор инициализации для этого пакета с присоединенным к нему ключом шифрования WEP. Таким образом, сид каждого последующего пакета отличается от предыдущего на 24 бита, а в остальном они сходны. За счет этого, равно как и недостатков шифра RC4, есть возможность извле-чения ключа WEP из большого количе-ства кадров (200-200 тыс.)

В реальности для выпол-нения такой атаки может хватить 5-10 минут.

Для этого используется инструмент Comm-View for WiFi, который представ-ляет собой коммерческую програм-му-анализатор для анализа трафика беспроводных сетей. Главная особен-ность этой программы – это то, что она переводит сетевую карту в режим мо-ниторинга, в котором захватываются все пакеты в радиусе действия сетевой карты, а не только те, которые пред-назначены ей, как это происходит при работе в обычном режиме. Однако для работы в режиме мониторинга необхо-димо использовать специальные драй-веры, которые идут в комплекте постав-ки CommView for WiFi. Стоит обратить внимание, что поддерживаются не все Wi-Fi адаптеры, поэтому рекомен-дуется ознакомиться со списком под-держиваемых и рекомендуемых адап- теров на сайте. u

Page 56: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 56

Б езопасность

Если ваш адаптер совместим с Comm-View for WiFi, то вы можете смело загружать и устанавливать 30-днев-ную ознакомительную версию программы. Сразу по-сле установки программы будет выполнена установка драйверов для совместимых сетевых адаптеров, по-сле чего можно выполнить первый запуск программы.

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

1. Откройте меню Настройка, выполните команду Установки, далее в открывшемся диалоговом окне на вкладке Использование памяти необхо-димо выполнить настройки, на как приведенном рядом изображени «Установки».

2. Далее настройте параметры хранения log-файлов, как указано на рис. «Параметры».

3. Последний этап настройки – указание правил захва- та пакетов. Для расшифровки WEP нужно выпол-нять захват только DATA-пакетов, с игнорировани-ем beacon-пакетов. Это делается в меню Правила.

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

Теперь можно переходить к собственно захвату тра-фика. Для этого нужно нажать на соответствующую кнопку с левого края панели инструментов Comm-View for WiFi.

В открывшемся диалоговом окне следует нажать кнопку Начать сканирование. Будут выведены бес-проводные сети, которые обнаружены в радиусе дей-ствия адаптера (рис. Мониторинг).

Далее нужно выбрать сеть, пакеты которой требуется перехватить, и нажать кнопку Захват.

Начинается самая длительная стадия взлома WEP. Если в данной сети передается мало данных, то этот процесс может затянуться на день-два, однако, если сетевой трафик велик, то нужное количество кадров можно захватить за 2-3 минуты. Объем передаваемо-го трафика вы можете оценить на вкладке Пакеты в окне CommView for WiFi.

Для того чтобы примерно оценить, сколько трафика нужно захватить, имеет смысл открыть в проводнике папку, в которой сохраняются log-файлы CommView for WiFi, и оценить общий размер этих файлов. Для успеш-ного взлома 64-битного ключа может хватить около 25-30 Мб, а для взлома 128-битного ключа – 50-60 Мб.

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

Теперь можно остановить захват и преобразовать весь захваченный трафик в CAP-формат. Для этого нажмите комбинацию клавиш Crtl+L. Откроется окно анализатора log-файлов. Из его меню необходимо выполнить команду Экспорт log-файлов, и указать Формат Wireshark/Tcpdump, а далее ввести имя файла, в который будет экспортирован захваченный трафик.

Будет выполнено преобразование захваченного трафика в CAP-формат. Процесс преобразования трафика из NCF (формат Conn View) в CAP, сопряжен с вероятностью зависания и завершения работы CommView for WiFi, поскольку пакеты, загруженные в ана-лизатор, хранятся в оперативной памяти, и операционная система может завершить работу программы, если она будет потреблять большое количество ресурсов.

После того как трафик захвачен, можно выполнять атаку. Для этого существует утилита Aircrack, которая распространяется по GPL-

Установки

Параметры

Мониторинг

u

Page 57: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 57

Б езопасность

лицензии, и поставляется с полностью открытыми исходными кодами.

После скачивания программы, пере-йдите в папку bin и выполните програм-му Aircrack-ng GUI.exe. В открывшем-ся окне нужно нажать кнопку Choose…, и выбрать созданный раннее CAP-файл (рис. Aircrack-WEP).

В окне графического интерфейса Airc-rack указывается метод шифрования, и длина ключа. После этого нажимается кнопка Launch, и откроется окно соб-ственно самой утилиты Aircrack, где бу-дет предложено выбрать точку доступа для взлома. Список содержит все те точки доступа, пакеты которых были захвачены CommView for WiFi, точнее их MAC-адреса и сведения о шифро-вании, а если были захвачены соответ-ствующие managnent-пакеты от этой точки доступа – то и их SSID, что зна-чительно упрощает поиск нужной точки доступа. Нужно ввести номер той сети, которую требуется взломать, и нажать Enter. Ключ для сети будет найден через 20-30 секунд, в зависимости от производительности компьютера (рис. WEP взломан).

Шифрование WEP

Защита

Лучшая защита беспровод-ной сети, которая использу-ет WEP-шифрование – это отключение самой сети.

Инструменты для взлома WEP широко распространены в сети, и их примене-ние не составит труда даже начинаю-щему взломщику. Также стоит помнить, что время, необходимое для взлома WEP-сети, обратно пропорционально передаваемому в сети WEP-трафику, и если в сети передается много данных, то злоумышленнику хватит и 5-и ми-нут нахождения в зоне покрытия сети, чтобы захватить трафик, а извлечение ключа он может выполнить вне сети.

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

Для защиты от прослушивания тра-фика следует использовать IPSec для шифрования всего сетевого трафика.

Однако даже с этими ухищрениями

WEP не позволит вам проверять под-линность пользователей, которые под-ключаются к сети. Для этого нужно ис-пользовать WPA\WPA2.

Теория

WPA и его дальнейшее развитие WPA2 представляет собой сильно усовер-шенствованную модификацию WEP.

1. Для подсчета контрольных сумм па-кетов используется MIC вместо ме-нее надежного CRC32.

2. Для шифрования данных использу-ется AES.

3. Шифрование данных участников сети друг от друга.

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

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

лагается ввести логин и пароль для доступа в сеть. Проверка учетных дан-ных выполняется на RADIUS-сервере, который в свою очередь, связывается с сервером аутентификации. В каче-стве сервера аутентификации исполь-зуется контроллер домена Windows Server 2008R2, его же используют как RADIUS-сервер.

Подобный подход к реализации WPA\WPA2 называется WPA-Enterprise. Он используется в крупных производствен-ных сетях, где уже развернута инфра-структура Active Directory.

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

Шифрование WPA\WPA2

Нападение

При рассмотрении WPA-PSK с точки зрения безопасности, сразу бросается в глаза момент проверки подлинности устройства. Как уже говорилось, для этого необходимо ввести пароль, кото-рый пересылается на точку доступа в зашифрованном виде. Если пароль со-

Aircrack-WEP

WEP взломан

u

Page 58: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 58

Б езопасность

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

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

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

Для этого необходим соответствую-щий беспроводной адаптер, например D-Link DWA-160. Инструменты для взлома используются те же – Comm-View for WiFi и Aircrack.

Настройки CommView for WiFi исполь-зуются те же, что и для взлома WEP. Аналогично выполняется мониторинг сетей, выбор сети для взлома, и начало захвата пакетов. Однако data-пакеты беспроводной сети нас не интересуют, так как они никак не помогут нам для взлома сети. Для того, чтобы послать пакет реассоциации, необходимо что-бы к точке доступа был подключен хотя бы один клиент (т.е чтобы было кому их посылать). Далее выполняется ко-манда Реассоциация узлов из меню Инструменты (рис. Посылка реассо-циации).

В открывшемся диалоговом окне необ-ходимо установить интервал посылки пакетов 10мсек, а количество пакетов – 100, после чего выбрать клиентов, которым будут посылаться пакеты, и нажать кнопку Послать сейчас не-сколько раз. Далее с периодичностью в 30-40 секунд необходимо выполнять посылку реассоционных пакетов в те-чение 2-3 минут. После этого можно нажимать кнопку Остановить захват на панели инструментов. Далее необ-ходимо переконвертировать захвачен-ный трафик в CAP-формат и запустить Aircrack (рис. WPA взлом).

Как видно из скриншота, требуется ука-зать имя сети, а также MAC-адрес точ-ки доступа и путь к словарю, по которо-му будет выполняться атака. Обратите внимание, что Aircrack не может ра-ботать с символами национальных алфавитов, включая русские буквы!

По нажатию кнопки launch начнется перебор пароля. Скорость атаки напря-мую зависит от производительности процессора. Для примера, на самом мощном из имеющихся в моем распо-ряжении процессоре Intel Core i7-950, скорость перебора достигает 3000 па-ролей в секунду.

По окончании перебора будет выведе-но сообщение, которое будет содер-жать ключ, если он найден, либо же сообщение о том, что ключ не найден.

Защита

Как вы уже поняли, WPA\WPA2 взломать гораздо сложнее, нежели WEP. Одна-ко, при использовании WPA-PSK оста-ется слабое звено – PSK-ключ. Если в качестве ключа используется словар-ное слово, то есть большой шанс того, что злоумышленник получит доступ к сети после словарной атаки. Устанав-ливайте сложные, не словарные 13-26 символьные пароли, которые содержат в себе русские буквы – и вы защище-ны от атаки на вашу сеть начинающим хакером. Однако, в производственной среде, лучше вообще отказаться от ис-пользования WPA-PSK, и развернуть там Active Directory и RADIUS-сервер.

Также стоит понимать, что защита беспроводной сети – это лишь «внешний рубеж» вашей инфраструк-туры.

Если вы реализуете в сети IPSec, это защитит вас от перехвата трафика вашей сети даже при условии взлома Wi-Fi.

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

Заключение

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

Используйте все вышеуказанные ме-тоды защиты, но также не забывайте правило: «лучший метод обеспечения безопасности беспроводной сети – это ее отсутствие». Не воспринимайте это правило буквально, но все же исполь-зуйте беспроводные сети только там, где они действительно вам нужны. n

Посылка реассоциации

WPA взлом

Page 59: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 59

W indows Phone

АвторСергей Абахов www.maginsoft.comБлог: http://msdeveloper.ru/blogs/MaginSoft/Твиттер: http://www.twitter.com/krestor85г. Москва

Локализовать или не локализовать: вот в чем вопрос

Тщательно изучая статистику про-даж, заметил, что основные прода-жи приходятся на три страны ‒ это

США, Великобритания и Австралия. По поводу первых двух стран никаких со-мнений не возникло, а вот Австралия заставила задуматься. По статистике покупок можно увидеть, что на 4 месте по загрузкам приложений идет Россия. По уровню загрузок разница между ними не слишком велика, но по уровню покупок разительна. В чем разница? Виноват в этом лишь менталитет на-ших граждан или дело в чем-то другом?

Разумеется, сразу приходит мысль, что для США, Великобритании и Австра-лии английский язык является родным. В России уровень английского языка у населения довольно таки плачевный. Да и по себе знаю, что приложения на русском языке покупаю охотнее, чем на английском.

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

Локализация

Локализовать приложение под Win-dows Phone 7 очень просто. Для этого сначала нужно все строки приложения вынести в файл ресурсов. Для соз-дания файла ресурсов нужно нажать на проекте правой кнопкой мыши, да-лее нажать Add и New Item. Выбира-ем Resources File и называем App-Resources. Нажимаем OK.

В этом файле будут храниться ресур-сы, используемые по умолчанию. От-крываем файл и вносим в него все строковые ресурсы, которые будем локализовывать. В поле Name вносим уникальный идентификатор строки, в u

Page 60: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 60

W indows Phone

поле Value саму строку.

После заполнения файла создаем новый файл ресурсов с именем AppRe-sources.xx-YY.resx. xx-YY – имя локали. Для России это ru-RU. После создания открываем файл и начи-наем переводить строковые ресурсы. В поле Name вносим идентификатор строки, соответствующий этой же строке в файле AppResources.resx, в поле Value вносим переведен-ную строку.

Заполнив файл, следует указать приложению, какие локали будут поддерживаться приложением. Для этого нужно от-крыть файл проекта (*.csproj) в любом текстовом редакторе и найти следующий элемент Xml ‒ <SupportedCultures>. Если этого элемента нет – нужно его создать. Этот элемент является дочерним для элемента PropertyGroup. После этого вносим в этом элемент имена локалей, которые будут поддерживаться приложением. Локали разделяются точкой с запятой. Например: <SupportedCultures>ru-RU;de-DE;</Sup- portedCultures>.

Теперь мы можем использовать ресурсы в приложении. Для этого создаем следующий класс.

public class LocalizedStrings{ public LocalizedStrings() { }

private static AppResources localizedresources = new AppResources();

public AppResources Localizedresources { get { return localizedresources; } }

}

Для доступа к строке из XAML мы используем этот класс. Вы-глядит это следующим образом:

<TextBlock FontSize=”26” Foreground=”Black” Margin=”10,0,0,0” Text=”{Binding Path=Localize- dresources.StringIdentificator, Source={Static-Resource LocalizedStrings}}”/>

Для доступа к строкам из кода используйте класс AppRe-sources.

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

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

Результат

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

По количеству покупок Россия вышла на второе место, обо-гнав Австралию и Великобританию и уступив США.

В российском Windows Phone Marketplace приложение вы-шло в топ по категории, заняв первое место. Сейчас прило-жение немного опустилось и занимает 4 место по категории.

По результатам эксперимента для себя я решил, что и в даль-нейшем буду локализовывать свои приложения. n

Page 61: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 61

А вторская колонка

Как вернуть надежность MS Project Server? Устоит ли он против Облака?

АвторВладимир Иванов Генеральный директор PM Consulting ServicesСайт: http://turboproject.ru/

Думаю многие заметили карди-нальное изменение на рынке систем управления проектами в

России в последние месяцы. Внедрен-цы и клиенты ушли в поиск альтер-натив традиционным решениям. Это общемировая тенденция, по отчетам Gartner хорошо видно, что рынок меня-ется и изменится еще больше. Облака вошли на рынок, предложив не только решения в 4 раза дешевле традицион-ных решений и не только небывалую совместимость с мобильными устрой-ствами, но и главное небывалую надеж- ность 99,8%-99,9% недостижимую на традиционных решениях.

Сам Microsoft не собирается быть Дон Кихотом воюющим против Облач-ной Ветряной Мельницы, фактически Microsoft предлагает заменить все се-мейство технологий SharePoint на их облачный аналог SharePoint Online в облаке Microsoft Office 365. Надо пони-мать, что Microsoft занимается бизне-сом и его не волнует судьба старых пар-тнеров и экспертов, которые отстали от развития и не освоили новые техноло-гии. То что Microsoft завел отдельную партнерскую программу для облачных партнеров и не признает в ней даже «золотые» заслуги, и сертификаты экс-пертов по старым технологиям, пока-зывает, что старых партнеров (и даже «золотых»!) в будущее он брать соби-рается только после кардинального об-новления экспертной команды.

Облака создали новый стандарт надежности

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

ми надежности старых решений. Сей-час, особенно для среднего и малого бизнеса, а также департаментов корпо-раций, появилась альтернатива не тра-тить деньги на стабилизацию старых систем, а получить облачное решение на базе технологий Microsoft Office 365 или их аналогов, забыв о зависаниях и прочих проблемах старых систем.

Вопрос надежности MS Project Server требует объективного анализа, т. к. с од- ной стороны появилась облачная аль-тернатива, а с другой стороны пробле-мы надежности MS Project Server обыч-но решаемы, но если не замалчивать технологические особенности в целях «быстрых продаж».

C одной стороны, MS Project Server до-бился в России впечатляющих успехов. Таких кейсов как Газпром-Нефть или Кубок UEFA нет у Primavera. С другой стороны, если вдруг с подачи продав-ца нарушается клиентом технология установки и обслуживания MS Project Server, все может превратиться в ноч-ной кошмар. Даже в таком случае на- дежность вернуть можно, однако стои-мость обеспечения надежности стано-виться в ряде случаев запредельной. Если клиент лишь немного отклонится от технологии, то до 40% бюджета и до 50% срока внедрения может уйти только на решение проблем MS Project Server, а не на бизнес-процессы и их автоматизацию. Если проблема надеж-ности честно обсуждалась с клиентом, то устранение ее стоит незначитель-ных ресурсов. Но признание серьезных дефектов может повредить продажам. Сейчас для всех экспертов по MS Project Server стоит выбор как строить продажи: либо пытаться скрывать про-блемы, либо их признавать и предла-гать пути решения.

В любом случае, необходимо вынести в бюджет внедрений трудозатраты на техническое обслуживание MS Project Server отдельной строкой.

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

Надо перестать менеджерам террори- зировать разработчиков и администра- торов вопросами в стиле «почему опять висит очередь MS Project Server?», а нужно выделить специалистам время на того, чтобы они сделали свою рабо-ту по стабилизации сервера управле-ния проектами Microsoft. Если кому-то нужно независимое экспертное обо-снование для выделения ресурсов на обеспечение надежности, перешлите спонсору проекта эту статью.

Если мы хотим работающие системы, а не игрушки, нужно перестать играть в игры утверждая, что «ошибки есть в любом программном обеспечении» и дело решается только звонками в тех-поддержку Microsoft. Вопрос в том, что MS Project Server далеко не «любое программное обеспечение», а уникаль-ное, с уникальной бизнес-моделью на-целенной на заказные и отраслевые решения. Такого класса ПО больше на рынке нет. Однако бизнес-модель MS Project Server предполагающая вмеша- тельство программистов для создания решения под заказ, перешла в дру-гую стадию. Фактически Microsoft уже рассчитывает, что программисты ис-правят (обойдут) и ошибки в его про-дукте. Возьмем к примеру вот эту «таб- летку». Если несколько снизить полит-корректность и назвать проблемы свои-ми словами, то эту «таблетку» нам при-шлось сделать в связи с тем, что MS Project Server был не способен не про-сто сохранять проекты, а еще при этом разрушал базы данных клиентов. Сей-час MS Project Server 2010 зависает на публикации проекта более 4000 задач, если опять же не использовать раз- u

Page 62: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 62

А вторская колонка

ные «таблетки». Приключение с Servi- ce Pack1, который должен исправлять ошибки Microsoft, а на деле разрушил множество серверов заказчиков пока-зывает, что одними только ресурсами Microsoft проблема надежности MS Project Server не решается. Все это зву-чит страшно для тех, кто решил купить «коробку+обучение», но это абсолютно не проблема, если MS Project Server внедряется по правилам эко-системы SharePoint, где программист с «на-пильником и кувалдой» неотъемлемая часть внедрения. Однако клиент дол-жен четко понимать что за продукт он купил, для каких целей, и как обеспе-чивается его надежность. MS Project Server и MS SharePoint ‒ это не продук-ты в коробке, это полуфабрикаты для разработчиков решений под заказ.

Не конечные пользователи, а партнеры Microsoft, реальные клиенты MS Project Server, фактически для партнеров, Mi-crosoft поставщик запчастей («плат-формы») из которых они могут со-брать решение под вашу отрасль. Так получится конечный продукт. Если на-рушить эту бизнес-модель, будут про-блемы не только со стабильностью, но и с функциональностью. Причем если у «сборщиков решений» возникают про-блемы с качеством запчастей постав-щика, то они имеют и другие варианты кроме ремонта. Можно заменить зап-части с дефектами на другие без де-фектов, например, целиком заменить MS Project Server на решения на базе Microsoft Office 365, где это возмож-но. Если проблемы большие, то рас-сматриваются уже варианты поставок запчастей от других вендоров. Это мы тоже рассмотрим в данной статье, как варианты получения стабильных реше-ний на MS Project путем использования технологий Oracle или Clarizen.

И все же, как купить и внедрить MS Project Server не попав в катастрофи-ческую ситуацию с надежностью и до-биться невероятной полноты функцио-нала? Начнем с культуры продаж.

Повышение культуры продаж MS Project Server - главное организационное условие технологии обе-спечения надежности

Начнем с базовой проблемы надежно-сти, она на самом деле организацион-ная ‒ в желании побыстрее выполнить план продаж, даже ценой создания чудовищных технологических рисков для клиентов. Как уже отмечалось, опытный профессионал может выпол-нить ряд технологических мероприятий и обеспечить надежность MS Project Server для промышленной эксплуата-ции. Хороший пример кейс в Триколор ТВ. Это внедрение было сделано бета-версии MS Project Server 2010 и, тем не менее, все работает очень надежно. Причина в том, что внедренец и клиент

доверяли друг другу. Внедренец честно признал наличие дефектов и указал на путь их обхода. Клиент потратив весь-ма небольшие ресусы успешно обошел проблемы.

Это нормальный путь. Однако если вы заметили, секрет надежности MS Project Server в том, что нужно снача-ла сказать клиенту правду о наличии серьезных дефектов, чтобы потом ска-зать правду как их обойти. В принципе любой честный продавец, который до-рожит своими клиентами так делает. У него просто нет выбора. Если он сол-жет и скроет проблемы, то ему больше клиенту ничего не продать.

Кроме продавцов, которые привязаны к клиентам и ими дорожат, бывают и «кочующие продавцы», задача которых только продать, а «после нас хоть По-топ». В этой технологии продаж лучше всего замолчать проблемы. Многие продавцы считают, что раз замолчали, то не солгали. Однако у Законодателя другая точка зрения:

«Продавец (исполнитель), не предо-ставивший покупателю полной и досто-верной информации о товаре (работе, услуге), несет ответственность, пред-усмотренную пунктами 1 - 4 статьи 18 или пунктом 1 статьи 29 настоящего Закона, за недостатки товара (работы, услуги), возникшие после его передачи покупателю вследствие отсутствия у него такой информации».

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

Что делать? Рекомендация очень про-ста.

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

Какие бы речи продавцов вы не слу-шали, стоит сначала заглянуть в ли-цензию на традиционное программное

обеспечение, а там написано «AS IS» (КАК ЕСТЬ). Т.е. поставщик ПО вам ничего не должен и ничем не обязан после покупки, как вы будете дальше решать вопросы ‒ это ваша проблема. Всегда стоить помнить об «AS IS» об-щаясь с продавцами, которых возмож-но больше никогда не увидите. До не-давнего времени все вендоры по сути продавали не продукты, а продавали компакт-диски с бумагой, в которой был полный отказ от гарантий к содер-жимому на этом диске.

Все поменялось когда пришли Облака, которые по сути торгуют «надежно-стью», поскольку они продают время работы системы, и впервые в исто-рии IT-индустрии вендоры несут ответ-ственность, что их продукты не просто работают, а еще и работают 99,9% вре-мени! Думаю скоро все будут обожест-влять новую Облачную модель сделок, т.к. она фактически уничтожила биз-нес-модель тотальной безответствен-ности производителей программного обеспечения. Сейчас Microsoft и Oracle начинают торговать бесперебойной ра-ботой ПО, а не компакт-дисками, у них нет выбора. Люди быстро привыкают к хорошему, если Microsoft и Oracle не перестроятся, то клиенты уйдут в чу-жие облака.

Вернемся к MS Project Server. Зачем Вам покупать продукт, который без спе-циального главного шамана, достаточ-но просто может зависнуть, перестать отображать что-то на Web-страницах или выкинуть еще кое-что поинтерес-ней, местами совершенно непредска-зуемым образом? Ответ прост ‒ вы купили платформу для отраслевых решений или решений под заказ со всеми плюсами и минусами такой сдел-ки.

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

Уникальность бизнес-мо-дели MS Project Server, как платформы для заказных или отраслевых решений

Если у Вас ограниченный бюджет и за-дачи ваши просты типа «только порт-фель проектов и табелирование», то вопрос экономической целесообраз-ности покупки MS Project Server от-крытый. Есть масса других продуктов, u

Page 63: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 63

А вторская колонка

которые это делают и даже легче на-страиваются. Именно на такой сегмент и нацелились Облачные вендоры типа Clarizen, и Gartner не рассматривает MS Project Server для таких задач.

Однако Gartner ставит MS Project Server рейтинг лидера в тяжелом классе, при-чем выше Oracle Primavera. Непра-вильное предположение, что эксперты Gartner не знают о проблемах надеж-ности MS Project Server, просто надо внимательно читать для какого класса решений они поставили рейтинг. Для этого класса проблемы надежности MS Project Server нивелируются.

Дело в том, что «лидеры» ‒ это самые дорогие продукты по Gartner, которые могут с лучшим качеством освоить са-мые большие бюджеты примерно за 3 года внедрения. На поверхностный взгляд, MS Project Server проигрыва-ющий в надежности и функциональ-ности той же Oracle Primavera вроде бы плохой выбор. Однако все наобо-рот и Gartner прав, Primavera ‒ плохой выбор, а MS Project Sever таит в себе очень важную магию. Магию «кастоми-заций».

Дело в том, что

только Microsoft предлага-ет на рынок платформу программирования для соз-дания систем управления проектами под заказ и от-раслевых решений. Вы мо-жете заставить MS Project Server адаптироваться под ваш бизнес или купить партнерское решение для вашей отрасли.

Программисты, применив те самые «напильник и кувалду» могут придать MS Project Server практически любую форму и удовлетворить самые без-умные желания клиента. Как говорит-ся: «Любой каприз за ваши деньги». Primavera и все остальные системы не имеют таких мощных средств разработ-ки дополнений и программной доработ-ки. Что выросло в Oracle ‒ то выросло, изменению не подлежит. Ваш бизнес должен подстроится под Primave- ra, даже если заложенные в ней сце-нарии не оптимальны для него и даже если аналитики Oracle не эксперты в вашем бизнесе. Сравнив эти два под-хода, Gartner справедливо посчитал, что Microsoft с его проблемами надеж- ности меньшее зло, чем негибкий Oracle.

Gartner дважды прав, расширяемость MS Project путем программирования просто феноменальная по степени гиб- кости. Например наш Turbo Project фактически внедрен в ядро Microsoft Project Professional. Технологии Micro-soft позволяют это сделать, поэтому кроме возможности перепрограммиро-вать MS Project Server под себя, вам еще доступен богатый набор «готовых

кубиков» из которых быстро можно складывать решения. Если заметили, программисты могут починить сам MS Project Server, даже если сам Microsoft не знает, что с этим делать. Партнеры Microsoft почти всегда могут с помощью программирования его починить, если заказчик дает на это ресурсы. Пример «таблеток» выше.

Отметим, что MS Project Server стал действительно членом семейства Sha-rePoint, т.к. ключевым партнерам по MS Project Server недавно пришлось пойти еще дальше, повторяя дорогу партнеров SharePoint. Ст. 1280 ГК РФ по сути разрешает производить деком-пиляцию продуктов в целях запуска интегрированного решения. Нам при-шлось также декомпилировать 100% MS Project Server, чтобы получить весь исходный текст написанный программистами Microsoft, т.к. в ряде случаев MS Project Server не может предоставить диагностической инфор-мации о том, что с ним произошло. При-ходится искать ошибки прямо в тексте программ Microsoft, вероятно следую-щий шаг их исправлять, как это делают партнеры по SharePoint. Анализ про-блем по исходным текстам Microsoft в топовых внедрениях становиться необ-ходимостью, т.к. Microsoft Premier Sup- port не может помочь клиентам, кото-рые не готовы отдать ему свою базу данных для воспроизведения ошибок.

Проблема надежности в крупных вне-дрениях развилась дальше. Факти-чески мне приходилось в проектах Microsoft Consulting Services отключать модули MS Project Server и создавать свои собственные, т.к. местами «по-чинка» начинала стоить дороже, чем просто переписать функциональность заново. Отметим, что в архитектуре MS Project замена родного модуля на партнерский заложена в очень многих местах. Это позволяет не только заме-нить модуль страдающий проблемами надежности, но и фактически снимает всякие рамки для развития MS Project Server. Недавно мы создали собствен-ный ресурсный модуль, т.к. например стандартные ресурсные механизмы MS Project ограничены для ряда про-мышленных решений.

Анализируя все это надо понимать, что нет реальных альтернатив Microsoft. В 2003м году я сам выбирал плат-форменного вендора между Microsoft и Oracle. Для профессионала было очевидно, что технологии Microsoft во многих местах недостаточно функци-ональные и недостаточно надежные. Однако Primavera, надежная как скала, но и в то же время гладкая как скала ‒ нет ни одной ручки, за которую можно было бы ухватится, чтобы начать соз-давать отраслевые решения. Только интеграция с «рядом стоящими» систе-мами, а это слишком примитивно для большинства отраслевых решений. То, что сейчас в качестве «отраслевых ре-шений» для Primavera, по сути прода-ются системы на базе 1С:Предприятия, показывает всю глубину проблемы с отсутствием собственной платформы. Разработка собственных механизмов табелирования рабочего времени или встроенных систем ресурсного норми-рования в Primavera ‒ это невозможная задача.

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

Любим мы или ненавидим Microsoft, но если нам нужно решение «под себя» или отраслевое, то альтернатив MS Project Server никаких нет. Это так же как любить или ненавидеть Windows ‒ все равно купить придется.

Но если наше решение не подразуме-вает перепрограммирование системы и нам нужно быстро решить типовые задачи, а также воспользоваться ге-ниальным по юзабилити (интерфейсу пользователя) MS Project? Как нам по-лучить портфель проектов и отметки об u

Page 64: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 64

А вторская колонка

исполнении, если не через MS Project Server?

Варианты есть конечно, придется по-смотреть на технологии других вендо-ров.

Какое еще ПО может быть сервером для десктопов MS Project?

Если MS Project Server со всеми его недостатками фактически не имеет разумных альтернатив для заказных решений, то десктоп MS Project в ре-альности практически не имеет конку-рентов вообще.

Часто мы серьезно рассматриваем кон-куренцию MS Project с Primavera или HP PPM. Однако стоит помнить, что десктопы MS Project ‒ это более мил-лиарда долларов в год, а остальные игроки порядка 100 миллионов. Поэто-му в масштабах всего бизнеса систем управления проектами, для Microsoft сражение с Primavera или HP PPM ‒ это как битва великана с боевыми гно-мами.

Надо заметить, что если можно долго с аргументами в руках критиковать ка-чество MS Project Server, то качество десктопов MS Project превосходное и на уровне стандартов Microsoft Office. Также много функций, также все удоб-но, также надежно.

Неудивительно, что после внедрения Primavera или HP PPM, внедренцы Oracle и HP, которые победили MS Project Server, никак не могут избавить-ся от десктопов MS Project, которые так прилипают к пользователям, не желаю-щим расставаться с самым удобным в мире инструментом планирования. Но решение само на поверхности ‒ можно просто итегрировать лучшее, что дела-ют вендоры.

Primavera Project Planner как сервер для клиентов MS Project

Primavera сама экспериментировала с тем, чтобы создать даже эмулятор MS Project Server для подключения к ней клиентов MS Project. Но высокая цена такого решения сделала его непопу-лярным.

Можно сделать другой вариант инте-грации, отказавшись от сервера Oracle и воспользовавшись скрытым потенци-алом Primaver Project Planner. Конечно это Oracle не понравится (он теряет на лицензиях в 10 раз), но это его пробле-мы. Главное, чтобы клиентам нрави-лось.

В Primavera Project Planner очень хо-рошие средства управления портфе-лем проектов, контрольными точками

и бюджетированием сверху вниз. Это исторически все встроено в сам клиент Primavera Project Planner.

Для энергетиков мы несколько раз де- лали решение, где портфель проек-тов из десктопов MS Project консоли-дировался именно Primavera Project Planner. Причем мы добились выполне-ния требований Федеральной Сетевой Компании для таких интегрированных решений.

В плане управления портфелем-про-ектом (если говорить о готовом реше-нии без доработок и компонент), то Primavera Project Planner функциональ-но превосходит MS Project Server, но стоит всего $2,500 против $10.000.

Недостаток в отчетности Primavera ис-правим путем создания заказного паке-та OLAP-отчетов с выводом их в виде сводных таблиц Excel. Сама Primavera Project Planner использует SQL-сервер для хранения данных. В случае MS SQL Standard даже не требуется отдельно покупать OLAP-сервер, Microsoft его просто подарит.

Получается решение очень дешевое, функциональное и главное надежное. Для строительных и промышленных проектов очень хорошее решение еще в плане того, что на Primavera не сде-лать производственный модуль с нор- мированием, а на базе MS Project Pro-fessional это возможно, через такие компоненты как Turbo Project.

Облако как сервер для клиентов MS Project

Другой вариант ‒ это использовать об-лачные сервисы для организации до-кументооборота и табелирования. Тут кандидат понятный ‒ Облако Clarizen.

Можно кроме импорта-экспорта MS Pro- ject-Clarizen еще сделать интеграцию в реальном времени. Точнее это сде-лано. Такое решение привлекательно еще тем, что данные проектов всегда остаются у пользователя в виде фай-лов. Поэтому если пользователь опаса-ется, что с облаком что-то случится, то данные он не потеряет в любом случае. Да и в облако он может отдавать лишь часть своих данных, которые реально нужны для коммуникационных целей.

Решение очень привлекательное по цене/качество, т.к. стоимость Clarizen в 4 раза ниже чем MS Project Server. То, что делает в MS Project Server/Share- Point программист, в Clarizen делает биз-нес-консультант настройками, и глав- ное облако никогда не падает и за это, наконец, отвечает вендор.

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

Но вернемся к MS Project Server, как нам его привести в чувство, если он нам нужен? Первый совет уже был ‒ избавиться от безответственных про-давцов, которые нарушают техноло-гию. Будем теперь конкретней.

«Не гонись поп за деше-визной, когда покупаешь оборудование для MS Project Server»

В принципе Microsoft довольно неплохо описал, как правильно установить MS Project Server в TechNet, вопрос в том, что многие IT-специалисты и продавцы считают ниже своего достоинства чи-тать документацию к продукту. u

Page 65: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 65

А вторская колонка

Вот документация, которую нужно обя- зательно прочесть и прочесть очень внимательно.

Если читать внимательно, то можно обнаружить, что желание запихать MS Project Server со всеми компонентами в один сервер, это нарушение технологии установки. Как говорится, читайте что написано мелким шрифтом для одно-серверной инсталляции: The guideline requirements for SharePoint Server 2010 are also valid for a Project Server 2010 installation with a small data set and light usage [Выделено Microsoft]». Если перевести прямолинейно ‒ ничего хо-рошего в односерверной инсталляции у вас не получится.

Читаем рекомендованные требования. Обратите внимание, что даже если вы ставите MS Project Server для двух с половиной пользователей, все равно требования такие и не меньше. Грубей-шая ошибка думать, что требования к MS Project Server просто линейно за-висят от числа пользователей. Ниже рекомендуемой конфигурации по «же-лезу», MS Project Server не просто начинает работать медленней, в нем внутри срабатывают таймауты и чаще всего просто зависает очередь серве-ра. Если вы поставили на меньшем по мощности оборудовании, и вам про-сто показалось, что MS Project Server работает, вы будете жестоко наказаны в дальнейшем нестабильной работой за пренебрежение к требованиями ин-струкции.

Итак минимальные требования:

{ Отдельный сервер для MS Project Sever: 4 процессорных ядра на частоте 2,5 Гц, 8 гигабайта памяти.

{ Отдельный сервер для MS SQL Server. В инструкции прямо намека-ют, что нужно 8 процессорных ядер и 16 гигабайт памяти.

Если вы ищете решения для управле-ния проектами для рабочей группы, то это симпатичные требования к обору-дованию, неправда ли?:)

И экономить нельзя. 4 ядра процес-сорных ядра требуются из тех сооб-ражений, что внутри MS Project Server четыре конвейера очереди и только под такую конфигурацию он и проте-стирован.

8 ядер для MS SQL Server нужны из тех соображений, что для MS SQL «буты-лочное горло» в архитектуре MS Project Server и ему нужно по 2 процессорных ядра на каждый конвейер очереди. Та-кая мощность требуется потому, что программисты Microsoft не смогли вну-три MS SQL Server реализовать мно-жество алгоритмов на «чистом» языке SQL-запросов. Очень интенсивно ис-пользуются «курсоры». Профессиона-лы знают, что такая техника программи-рования способна убить даже мощный SQL-сервер, т.к. вынуждает его быть не сервером баз данных, который за одну

операцию перерабатывает сотни запи-сей, а просто медленным итерпритато-ром, который их перебирает по одной.

Ядро MS Project Server так устроено, что в случае если не хватает ресурсов, оно не начинает работать медленней. Поскольку ядро «многопоточное» и нужно решать задачу как синхрони-зировать параллельно обрабатывае-мые потоки данных, то разработчики Microsoft не смогли найти другого ре-шения как поставить таймауты. Про-ще говоря, если не хватает ресурсов, внутри MS Project Server начинают каскадом срабатывать таймауты и как типичное следствие ‒ зависание оче-реди MS Project Server с фактическим блокированием его работы.

Никогда не экономьте на «железе» и буквально сле-дуйте инструкции Microsoft.

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

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

Но особенно жестоко чувствуется от-сутствие описания к дисковой систе-ме в случае виртуализации.

Виртуализация и VMWare как фактор критических рисков для надежной рабо-ты MS Project Server

Виртуализация официально поддержи-вается MS Project Server, но опять же читайте, что написано мелким шриф-том. Нигде не сказано, что поддержи-вается виртуализация VMWare, более того передаю вам из первых рук от разработчиков MS Project Server по их просьбе, что VMWare официально не поддерживаемая платформа. Почему VMware работает плохо, расскажу под-робней дальше, но отмечу, что проте-стирована только виртуализация на Microsoft Hyper-V.

И читаем мелкий шрифт: «We do not recommend running SQL Server on a virtualized machine. The competition for resources on a virtualized machine can substantially decrease the performance of the SQL Server». Какой интересный документ! Ранее Microsoft и VMware по-казывали множество тестов по «успеш-ной» виртуализации SQL-серверов. Ведь признание того, что есть прило-жения практически несовместимые с виртуализацией, ставит под сомнение

стратегию продажи «кочующих про-давцов» виртуальных систем. Однако опытные администраторы давно знают, что виртуализация SQL-серверов это просто обман некомпетентных покупа-телей. Microsoft даже указал не только на несовместимость с виртуализацией, но правильно указал на ее основную причину ‒ конкуренция за ресурсы.

SQL-серверы очень сложные систе-мы, сопоставимые по сложности с операционными системами. Внутри промышленного SQL-сервера живет система искусственного интеллекта, которая за 0.01 сек может сотворить чудо. Если просите SQL-сервер сде-лать операцию, искусственный интел-лект взвешивает «стоимость» работы с памятью, процессорами и жесткими дисками. Это очень тонкая система, она учитывает малейшие накладные расходы оборудования, такие как лиш-ние перемещения головок в жестких дисках и т.п. Система виртуализации живет своей жизнью и может просто отобрать какой-то ресурс «на время», если это нужно другой виртуальной машине. Придуманный SQL-сервером план (query plan) выполнения становит-ся неоптимальным и происходит дегра-дация до 10 раз, а дальше таймауты и как мы помним, MS Project Server после этого висит.

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

Если приглядеться, то копящийся нега-тив на виртуализацию имеет туже при-чину, что и негатив на MS Project Server. Она не технологическая, а организа-ционная ‒ это «кочующие продавцы» скрывающие недостатки и ограничения технологий с целью быстрых продаж.

Это видно вот по какому фактору. Опыт-ному специалисту продающему систе-му виртуализации хорошо известно об проблемах выше и он может их очень сильно минимизировать. Microsoft пи-шет как: «For the virtual machine that you are running SQL Server on, we recommend that you select the “pass through” option for the disk type (rather than dynamic, or fixed). If this is not an option, you should utilize a fixed disk size rather than a dynamically sized virtual disk». Проще говоря, нужно отключить виртуализацию жестких дисков и соз-дать дисковый отдельный массив для SQL-сервера. Однако если продавец виртуализации это признает, начнет-ся рушиться миф об универсальности виртуализации и ее тотальной совме-стимости, это может быть причиной, почему клиент откажется от сделки. Поэтому клиентам поставляются до-рогие системы виртуализации, которые не имеют выделенных массивов для SQL-серверов. Причем делается это умышленно и зная о проблемах, кото-рые от этого появятся у клиента. u

Page 66: 03 (07) 2012 MSDeveloperRU

03 (07) 2012 MSDeveloper.RU 66

А вторская колонка

Если сравнивать Hyper-V и VMware, то в целом надо признать, что рабо-тает лучше Hyper-V при соблюдении всех инструкций, т.к. виртуализируется только MS Project Server, а не MS SQL. В среднем по империческим тестам, MS Project Server быстрее на Microsoft Hyper-V, чем на VMware на 20%, но воз-можно именно эти 20% разделяют вас от «границы смерти», где поджидают таймауты.

Опять же проблема не в технологии VMware, а в продавцах. Сама VMWare имеет более совершенные средства по динамическому перераспределению ресурсов процессоров и памяти меж-ду виртуальными машинами. Однако продавец не может сказать клиенту правду, что такие сложные технологии требуют серьезного сертифицирован-ного специалиста для ее настройки. Причем именно сертифицированного и обученного самим вендором, а не «бы-валого». Для MS SQL динамическое исчезновение памяти и процессоров создает также проблемы адекватности его алгоритмов в такой ситуации. Вли-яет это не так сильно как проблема с жесткими дисками, но потерять 10% производительности можно. Опять же этого может хватить, чтобы поймать «таймауты» MS Project Server. Прода-вец виртуализации не может сказать клиенту правду о дорогом обслужива-нии редкими специалистами, т.к. кли-ента это может испугать. С Hyper-V ситуация лучше именно потому, что он больше рассчитан на непрофессио-нальное администрирование. Ресурсы в Hyper-V чаще всего администраторы прост фиксируют и не включают дина-мическую балансировку.

Для меня был очень показателен один случай у клиента, который приобрел систему VMware с оборудованием поч-ти за 1 миллион долларов и при этом все виртуальные машины работают на-столько плохо, что обычный домашний компьютер за 2 тысячи долларов по-ставленный рядом с таким же ПО на-чинает казаться мейнфреймом. Изучив настройки оборудования я обнаружил, что не функционирует половина диско-вого массива. Причем если попытаться ее подключить, появляется запрос на лицензию. На вопрос продавцу: «Что все это значит?». Последовал очень простой ответ, что «настало время за-платить еще». Система была продана специально с дефектом проектирова-ния, чтобы с клиента получить еще де-нег. И это не единичный случай, а как раз норма. Вот так относятся продавцы к своим клиентам в России и вот в ка-ких условиях созданных продавцами мы внедряем решения.

Как видим запустить MS Project Server на виртуализации можно, но серьезно мешают кочующие продавцы, которые ради быстрой продажи умышленно соз-дают условия для грубого нарушения технологии.

Заключительные рекоменда-ции по надежности MS Project Server

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

{ Помните, если вы купили MS Project Server, то значит хоти-те его дорабатывать или ставить к нему компоненты, иначе ваши затраты на техническую поддержку не окупятся.

{ Доработки под заказ и готовые отраслевые решения ‒ это повод смириться со стабильностью MS Project Server, т.к. те-стирование в таком внедрении это норма.

{ Десктоп MS Project на порядок более надежен и стабилен, чем MS Project Server, принимая решение, учитывайте это.

{ Если вам не нужны доработки SharePoint для MS Project Server, изучите альтернативные сервера для консолидации планов из настольных MS Project.

{ Внимательно читайте инструкции Microsoft по установке и не отступайте от них.

{ Не экономьте на оборудовании.

{ Остерегайтесь виртуализации без продуманной архитекту-ры, предпочитайте Hyper-V вместо VMware.

{ Почти всегда для внедрения MS Project Server нужен «ша-ман», но он может быть тоже бессилен, если вы кардиналь-но нарушили технологию.

Список честных шаманов по MS Project Server

Наша компания (PMCS) строит отношения с клиентами на чест-ности и мы предупреждаем о рисках и рассказываем как их обойти.

Но мы не единственные на рынке, кто принципиально не строит бизнес на обмане. Вот список проверенных внедренцев.

{ Microsoft Consulting Services (звоните прямо в MCS консуль-тантам)

{ Acceleration

{ ICS

{ Conteq

{ Bi to be

{ PMCS

Консультанты Microsoft или партнеры в этом списке будут ве-сти сделки честно и не только проведут вас невредимыми через «минное поле», но и еще создадут или сразу поставят отрасле-вое решение для вашего бизнеса. Возможно другие партнеры Microsoft также предупреждают о технологических рисках, но автор статьи не видел их договоров и документов с внедрений, чтобы об этом судить. n

Page 67: 03 (07) 2012 MSDeveloperRU

Рекл

ама

Сайт журнала MSDeveloper.RU

Каждый день свежие новости

Каждый месяц новый номер журнала

Блоги пользователей

Система личных сообщений

Большой тематический форум

Календарь важных событий

Стена друзей

Подборка книг

Горячие вакансии

Бесплатная подписка на журнал