Определение места ошибки в исходном файле

Относительно недавно я писал про Singleton и там была у меня не решенная проблема с тем, что не выводилось точное место возникновения ошибки. Анализ ошибки проходил как надо, информация дополнительная выводилась, но это было мало. Привычный шаблон работы, когда двойной клик по тексту ошибки приводил к навигации на место ошибки не работал. Это безмерно огорчало.

После плодотворного общения с программистами PostSharp, оказалось, что это была ошибка в последней сборке и новый релиз, начиная с 4.0.41, ее исправляет. Дальше я хочу отдельно обратить внимание на то, что надо делать и рассказать немного о том, как вообще можно получить эту информацию в C#: до версии 4.5, с версии 4.5 и старше.

PostSharp

Эта часть статьи в целом задумана как обновление и привлечение внимания к статье про шаблон Singleton. Я ее обновил, но тем не менее.

Использование Архитектурного фреймворка из состава PostSharp рано или поздно приведет вас к тому, что надо будет уведомлять программистов об ошибках/недочетах. Лучше всего это делать с помощью специализированных классов, которые построены с учетом специфики работы PostSharp на этапе сборке проекта. К таким специализированным классам относятся:

  • MessageLocation – статический класс, который позволяет узнать место ошибки (строка, файл) на основе служебной информации о составной части класса (MethodInfo, ConstructorInfo и так далее).
  • Message – класс со статическими и динамическими методами, который помогает сформировать сообщение для отображения для конечного пользователя – программиста.

Общий шаблон работы с этими классами выглядит так:

Подробнее

Принцип наименьшего удивления

Наконец-то появилась запись с выступления SECR-2013. Может она появилась и не на днях, но заметил я ее не так давно. Так что делюсь и оставляю себе, чтобы не забыть.

20131025-27-Принципы наименьшего удивления в разработке API приложения from Stas Fomin on Vimeo.

Поведение при подписке на события

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

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

sample

Логика работы приложения выглядит следующим образом. При выборе элемента из списка картинка предпросмотра обновляется на произвольную из выбранного альбома. Согласитесь, что все очень просто, так?

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

Код в реальности выглядит вот так. Т.е. это то, как вы его напишите с первого раза. Собственно я написал так же.

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

Итак, что вы ожидаете от такого кода? Посмотрите внимательно на названия методов, событий – решите для себя, что вы ожидаете.

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

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

Это очень странно на первый взгляд, так как я подписываюсь на событие и ожидаю, что его получат все заинтересованные компоненты, и обработка не прервется на самом интересном месте. Для того, чтобы сработало передвижение на новый элемент из listBox, необходимо дописать IsHandled = false:

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

На мой взгляд надо сделать два события:

  • ArrowNavigationCommandReceived – нет возможность использовать IsHandled для прерывания цепочки обработки.
  • ArrowNavigationCommandReceiving – есть возможность использовать IsHandled.

Ближайшая аналогия прослеживается с событиями Closed и Closing для окон (WinForm, WPF).

Что вы думаете по этому поводу? Комментарии как всегда приветствуются.

UPD: голосование пока что запилить не могу.

[poll id=»2″]

Hard’n’Heavy!

Логика на INotifyProperyChanged

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

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

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

Я уже не раз писал и говорил насколько мне не нравится явная реализация INPC при реализации MVVM для WPF, но недавнее открытие в проекте коллег не смогло меня оставить равнодушным. Честно сказать, я не представлял, что таким образом можно построить логику приложения, но что есть, то есть. Итак, не будем более затягивать вступление и обратим взор на код.

Подробнее

Работа с MS Exchange — II

Составление строки поиска

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

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

  • Создаем необходимые фильтры
  • Объединяем их в коллекции по логическому использованию «И» или «ИЛИ»
  • Создаем специальные коллекции для использования

 

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

Подробнее

Работа с MS Exchange — I

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

Когда ко мне пришла задача по вытаскиванию вложений из писем с нашего Exchange сервера, я весь внутренне содрогнулся, скривился и постарался откреститься от этой задачи, так как в памяти еще до сих пор свеж опыт работы с VSTO. Я думал, что это будет такой же кромешный ад и страдания в попытке разобраться в логике компонентов, что и для excel и word.

Первые предположения сделали за меня, подумав, что надо будет соединятся с Outlook и через него выдирать сообщения и вложения к ним. К тому письму приложили до кучи пример, мол вот уже все готово, только оформите нам службу красивую. В примере конечно же использовались обертки над COM, с заголовками с структурами работы с С++. С этим языком я работал только в университете и как-то мне не улыбалось снова к нему обращаться, так как не умею на должном уровне. Помимо самой реализации, с которой возникли бы большие проблемы при желании как-то расширить пример, а такие желания возникают обязательно, была проблема безопасности Outlook, который спрашивал разрешения пользователя каждый раз, когда бы служба лезла к ящику. Кроме того реализация не учитывала новые клиенты и Office 2013 шел лесом. В общем, косяков слишком много, чтобы делать что-то серьезное таким способом.

Мир не мог быть так жесток и пришло спасение в виде EWS Managed API от самой MS. Полностью управляемый код для общения с сервером Exchange, что на мой взгляд гораздо лучше для работы с почтой, чем использовать API Outlook.

Кратно о возможностях библиотеки:

  • Возможность создавать, читать, манипулировать всеми пользовательскими элементами сервера (письма, контакты, календарные события, правила).
  • Не требуется пакет офис на целевой машине
  • Автоматический поиск сервера. Т.е. вы вводите только имя пользователя, пароль и имя ящика, все другие необходимые данные для связи библиотека постарается найти сама, в точности как Outlook.
  • NTLM и явная авторизация.

Все подробности по библиотеке и возможности, вы сможете прочитать на официальной странице.

Что будет показано в статье?

Я планирую показать далее следующие техники:

  • Поиск писем и папок
  • Создание и отправка писем. С вложениями.
  • Удаление писем.
  • Ответ и форвардинг писем.
  • Получение писем, уведомления, извлечение вложений.

Подробнее

Создание проектов с NuGet и ReSharper

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

 

Hard’n’Heavy!

 

 

WPF Exception Viewer

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

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

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

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

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

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

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

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

Подробнее

EF5 RF CF — Force Recovery Mode

Сложность 200

Или как заставить базу думать, что у вас новая модель.

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

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

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

Подробнее

Эволюция сервисных методов

Сложность по шкале Microsoft 200-300

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

В данном случае под эволюцией подразумевается то, как инфраструктурно выглядит метод, а не его функциональная эволюция (рефакторинг). Описывать, как всегда, я собираюсь свой личный опыт,  то, на чем я набил шишки.

Простейшие

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

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

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

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

Подробнее