Async/Await для .Net 4.0

Сложность 200-400

Буквально на днях в блоге разработчиков Base Class Library промелькнуло известие о том, что теперь можно использовать async/await и для кода написанного на .Net Framework 4. А это значит можно использовать удобный подход для асинхронной работы, даже если пользователи вашей программы до сих пор сидят на «старой, доброй XP» по тем или иным причинам. Естественно такая новость не могла пройти мимо меня, чтобы я не попробовал как оно на самом деле в использовании. Забегая вперед, и что вполне ожидаемо, работает все точно так же как и в 4.5 за исключением некоторых нюансов в процессе разработки. Но обо всем по порядку.

Команда разработчиков анонсировала пакет дополнений, который позволяет использовать await в Visual Studio 2012 (в предыдущих версиях работать не будет). Выпущенный пакет может быть применен к следующим платформам (указанной версии или выше):

  • .NET Framework 4.0 (with KB2468871)
  • Silverlight 4
  • Windows Phone 7.5
  • И портируемые библиотеки опирающиеся на указанные платформы.

Т.е. это не встроенная фича .net 4.5?

И да и нет. Очень заманчиво думать, что новые ключевые слова await/async в C# являются чистым новым функционалом языка. В некоторой степени это так: компилятору необходимо проделать достаточно много сложной работы с вашим кодом, чтобы он мог ожидать операции.

Принимая вышесказанное во внимание, разработчики ожидают возможность использования await как только они переходят на новую студию – независимо от платформы языка. Если вы задумывались о том, как реализовано большинство фич языка, то вы можете догадаться, что многие вещи не просто данность и особенность языка. Множество конструкций языка опираются на вполне конкретные API, к примеру, методы расширения опираются на ExtensionAttribute, а foreach зависит от интерфейса IEnumerable. В случае с await потребуется давно любимый класс Task и некоторая хитрая обвязка, которая делает возможным использование await.

Подробнее

SQL Tips & Tricks

Сегодня в программе несколько интересных наблюдений и заметок по поводу SQL Server. Советы и заметки ниже применимы к любым актуальным версиям SQL Server (таковыми считаются все версии от 2005 и новее). Итак:

  • Получение изменившихся данных без триггеров
  • Select vs Set для установления переменных
  • Забытое дополнение для TOP

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

Получение изменений без триггеров

Действительно большинство пользователей MS SQL Server думают, что триггеры это единственное место где можно использовать виртуальные таблицы Inserted и Deleted, с помощью которых можно получить данные об измененных данных в результате выполнения запросов с Insert, Update или Delete. Но, как вы уже наверно догадались, это не так.

Любые изменения в данных, которые проводятся с помощью DML операций могут быть «захвачены» в специальные виртуальные таблицы упомянутые выше. Для этого в запросе надо использовать служебное слово output и перечислять поля которые вы хотите записать в нужную таблицу.

Подробнее

GC & Events

Недавно прочитал книгу Under the Hood of .Net Management от компании Red Gate и хочу всем ее посоветовать к прочтению, так как написана она очень доступно и хорошо, с картинками, примерами и рекомендациями. Вообще тема управления памятью в .Net достаточно интересна и познавательна, но в большинстве ресурсов описание ее идет с какими-то неимоверными сложностями или же с недостаточно наглядными примерами, на мой взгляд. Отчего не остается в голове цельной картины как же все работает в теории, так как авторы книги признаются, что нет точного описания управления памятью и того как сборщик мусора выполняет свою работу. Есть общие положения и структуры, но все остальное очень сложное и в 99,999% случаев не требуется знать всю начинку и как-то подсказывать сборщику мусора как работать. Т.е. в применении к сборщику мусора справедливо высказывание «помогать – только портить».

Итак, по мотивам книги хочу коротко пересказать как работает сборщик мусора, как авторы советуют писать метод Dispose() и некоторые мои соображения и эксперименты с событиями (которые event) в этом ключе.

Подробнее

Теневое копирование библиотек

сложность 200

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

Теневое копирование (Shadow Copy) – позволяет работать с заблокированными файлами. Приложение может блокировать и обычно блокирует все библиотеки которые были использованы/используются в процессе работы приложения, файлы с которыми ведется работа. Под работой может подразумеваться изменение, перезапись, удаление, переименование и так далее.

Зачем оно надо?

Теневое копирование позволяет приложению не зависеть от библиотеки расположенной в директории загрузки все время работы, так как она копируется в приватную директорию в профайле пользователя. Таким образом, например, работает IIS с ASP.NET приложениями.

На мой взгляд, данная технология может быть полезна в следующих случаях:

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

После того, как определились что такое «теневое копирование» и зачем оно нужно, можно собственно перейти к обсуждению реализации.

Подробнее

Теневое копирование библиотек

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

WPF Exception Viewer

Сложность 100-200

Достаточно давно я писал о том, как работать (обрабатывать) с исключениями при использовании класса Task из Task Parallel Library (TPL), все описанные способы действительно работают и проверены на практике уже много раз и отлично меня спасают и упорядочивают работу с потоками, особенно с получением исключений. Однако тогда я упустил важный момент как еще централизованно можно получать исключения и никак не был освещен вопрос удобства работы с исключениями: отображение и коммуникация от пользователя. Сегодня собираюсь наверстать упущенное тем более под руку подвернулся удобный и простой набросок от MarkLTX с CodeProject.

Как оно бывает обычно

Обычно отчет об ошибке выглядит примерно следующим образом:

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

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

Так же пользователи не знаю, что текст можно копировать нажав Ctrl+C и высылают FullHD скриншот с ошибкой. Конечно весело порой посмотреть на чужие рабочие столы, но это быстро надоедает.

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

Подробнее

Валидация свойств с помощью атрибутов в WPF

Сложность 200-300

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

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

Традиционный способ валидации

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

Подробнее

PostSharp Threading Toolkit

Сложность 100

В завершении небольшого цикла о PostSharp Toolkits стоит так же поведать о средстве для обнаружения дэдлоков в программе. Для внедрения такого функционала потребуется по одной строке кода в AssemblyInfo.cs в каждом проекте, зато польза должна быть ощутимой. Но обо всем по порядку. В работе приложений большей всего раздражает «замерзший» интерфейс. Причин для этого может быть много: как неправильно распределенные операции по потокам, но через какое-то время интерфейс отмирает, так и дэдлоки в программе, которые вешают приложение намертво.

Определение для deadlock

Deadlock – ситуация когда два или более ресурса ждут завершений действий друг друга, но так никогда и не дожидаются. Если вы обширно используете конструкцию lock, то потенциально вы можете оказаться в описанной ситуации. Существует 4 основных условия для возникновения дэдлока:

  1. Ограниченное количество экземпляров для ресурса. В случае использования класса Monitor в С#, это число ограничено 1 экземпляром, так как Monitor создает взаимоисключающую блокировку. Напоминаю, что lock{…} это синтаксический сахар для класса Monitor.
  2. Возможность удерживать один ресурс и одновременно запрашивать другой. В C#, как и в большинстве языком, это проделывается легко, например:
  3. Отсутствие преимущественного освобождения ресурсов. В C# это значит, что один поток не может заставить другой поток освободить ресурсы.
  4. Цепная зависимость условий ожидания. Пусть поток 1 ожидает поток 2, поток 2 ожидает поток 3, а поток 3 ожидает 1. Получилась цепная зависимость, которая приводит к дэдлоку.

Если какое-либо условие исключить, то взаимная блокировка ресурсов невозможна. Логично предположить, что для решения проблемы дэдлоков необходимо чтобы хотя бы одно условие не выполнялось в любой момент работы приложения. К сожалению для больших систем описанные условия возникновения дэдлоков возникают на удивление просто. В теории, взаимная блокировка ресурсов может быть решена путем прекращения одного из потоков, который вовлечен в создание дэдлока. В то же время в большинстве ситуаций прерывание потока опасная операция, так как при этом данные должны быть корректно возвращены в исходное состояние. Некоторые продвинутые техники, такие как lock leveling могут предотвратить появление блокировок. При использовании упомянутой техники, все блокировки получают свой номер и поток может получить только блокировки с номером больше своего. В целом можно представить сложность данного решения и что такой подход может лишить нас многих плюшек .Net Framework, так что это не из разряда практических решений задач.

Подробнее

PostSharp Thread\Dispatcher Toolkit

Сложность 100

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

Итак, сегодня в программе тулкит, который позволяет с помощью атрибутов указать выполнение метода в отдельном потоке, а так же указать какие методы вызывать в потоке UI. Собственно вот и весь функционал.

О том как решаются эти проблемы в «традиционном» стиле, я рассказывал в статье про эволюцию сервисных методов, там же описана библиотека MakeMeAsync, которой я с удовольствием и активно пользуюсь на данный момент. Не буду повторятся какие альтернативы существуют. Сейчас уже официально выпущен .Net Framework 4.5 c поддержкой конструкции async\await, так что я надеюсь что использование монструозных конструкций для выполнения кода асинхронно будет сходить на нет.

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

Подробнее

INPC Framework

Сложность 100

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

Некоторые библиотеки по реализации интерфейса предлагают в «полезную нагрузку» IoC контроллеры и перехватчики в стиле АОП.

Хотя до недавнего момента я использовал часто Kind Of Magic для решения этой проблемы, я неоднократно сталкивался с тем, что люди в свойства запихивают огромный функционал и этим отрицают целесообразность использования средств в духе Magic. Либо же начинают рассказывать о том, что должен быть полный контроль кода – все надо писать руками.

Относительно давно были анонсы о фремворке от Sharpcrafters, но я как-то пропускал их в силу разных причин и загруженности, но наконец дошли руки и я хочу вам рассказать о PostSharp Domain Toolkit, он же INPC Framework.

Коротко о главном

Распространяется PostSharp Domain Toolkit c помощью NuGet пакета. Установить его можно выполнив команду:

Install-Package PostSharp.Toolkit.Domain

После чего установится как сам тулкит, так и PostSharp. Можно начинать работу.

Самый простой и общий сценарий будет заключатся в добавлении атрибута NotifyPropertyChanged к вашей вьюмодели. Всё. Больше ничего делать не надо. Автоматически «магическим» образом будут обработано подавляющее большинство всех сценариев работы в среднестатистическом приложении.

Подробнее