Postsharp: авторизация и аутентификация
Одно из самых востребованных применений аспектно-ориентированного программирования это вынос обслуживающего инфраструктурного кода, который часто повторяется в системе, в отдельный класс. Что в свою очередь является проявленем принципа единой ответственности (SRP - Single Responsibility Principle). Очень часто задачи авторизации и аутентификации разбросаны по всему коду проверяя права доступа пользователя. Следствием этого является большая трудоемкость изменений в этой немаловажной части логики, а так же ее общая проверка. Принцип единой ответственности говорит о том, что должна быть только одна причина для изменения класса, так что все что относится к авторизации и аутентификации просто просится в отдельные классы.
Основные методы аутентификации обычно не то, что используется по всему приложению. Например в веб приложениях ввод данных для аутентификации и сама аутентификация происходит на одной странице, после чего информация о пользователе хранится в каком-либо токене со сроком годности. Благодаря этому пользователь может автоматически входить в систему в течении срока работы токена. Таким образом единственным кодом, который пронизывает все страницы приложения будет проверка того, что пользователь до сих пор в системе. Конечно, вы можете использовать PostSharp для такой проверки, но это не лучший способ применения, по моему мнению.
Ненавистный INotifyPropertyChanged
Да, уже из названия видно мое отношение к интерфейсу INotifyPropertyChanged и к его явной реализации в проекте. Я покрываюсь мурашками, и меня бросает в дрожь только при одном виде такого кода:
private string description;
public string Description {
get { return description; }
set {
description = value;
RaisePropertyChanged("Description");
}
}
Какая растрата места на экране, какая колоссальная неэффективность написания кода, какая хрупкость в работе. Передача строковых переменных не может быть не хрупкой.
А когда таких свойств прописано с десяток и все это обернуто в регион (#region), то взгляд стекленеет, становится безжизненным и мозг отказывается верить в реальность происходящего. Конечно, самое большое зло от такого подхода – потеря времени на написание и на чтение.
Более того, это чистый инфраструктурный код, который не должен попадаться на глаза в логике приложения, только если специально его искать. Реализация INotifyPropertyChanged прямой и явный кандидат на реализацию в рамках аспектного-ориентированного программирования.
К сожалению, при разработке пользовательского интерфейса на WPF такая реализация «в лоб» встречается до сих пор сплошь и рядом. Не далее чем неделю назад вычищал такой код из рабочего проекта. Я бы порадовался за трудолюбие и усидчивость разработчиков пишущих такой код, но я склонен думать, что программист должен быть ленивым. В хорошем смысле. Так что лучше потерять немного времени на настройку и потом быстро-быстро все сделать. Далее я опишу 4 более-менее различных подхода к решению данной проблемы.
PostSharp. Безопасность полей класса
И снова речь пойдет о PostSharp! =) Сегодня я хочу рассказать об аспекте OnFieldAccess (или в версии 2.0 LocationInterceptionAspect), который позволяет держать контроль над использованием свойств и полей класса. В прошлых статьях я рассказывал о применении аспектов на вызовы методов и о задачах, которые могут быть решены с их помощью. В целом, все те же задачи применимы и к полям: логирование изменения значений полей, защита доступа по ролям. Кроме этого можно организовать защиту полей от записи, декларативную проверку значений, уведомление других объектов об изменении значений.
Многие эти задачи при реализации традиционным способом, порождают необходимость написания кучи однородного кода. PostSharp позволяет избавиться от размазывания кода по всем слоям и консолидирует все проверки в одном месте, что, на мой взгляд, легче для понимания и дальнейшего внесения изменений.
Так же, в этой статье я рассмотрю такую возможность PostSharp, как проверка возможности применения аспекта на этапе компиляции. Я считаю, что это замечательная возможность, которой не стоит пренебрегать в дальнейшем. Для кого-то это может даже стать решающим моментом в применении данного продукта. Я знаю таких людей, которые ни за что не будут пользоваться продуктом, который не будет их строго ограничивать, а тут они имеют возможность написать себе такие ограничения и радоваться жизни. Да и в случае дистрибуции третьим сторонам вашей библиотеки это будет полезно.
PostSharp. Безопасность
Продолжаем подробный разговор о аспекте OnMethodBoundary. Данный аспект применяется, когда у вас есть доступ к исходным кодам метода и вы хотите отслеживать события начала вызова метода, конец вызова, исключение и успешность завершения. Все это делается переопределением методов OnEntry, OnExit, OnException и OnSuccess соответственно.
Применение аспекта OnMethodBoundary рассмотрим на примере задач о разрешении или запрещении тех или иных действий, логирование интересующих нас действий, генерация служебного кода. Так же с помощью данного аспекта можно декларативно указывать запускать ли методы в отдельном потоке или нет, но это рассмотрим подробно и в деталях в другой статье. Сегодня на повестке дня безопасность – это будет показано в одном приложении, исходный код которого можно свободно скачать и поиграться с ним.
Security
При создании более-менее сложных программных продуктов, часто требуется определять несколько ролей для работы с программой. В самом минимальном случае это администратор и пользователь. Для такого набора ролей можно как-то вывернутся по-простому, например, разграничить экраны для этих ролей, может даже каким-то образом сервисы. Но это не избавит от ошибок использования методов. При развитии программы могут появляться новые роли, менятся ответственность старых, и тогда придется отслеживать какой метод доступен для какой роли. В коде это должно превратиться в сущий ад и добавление новой роли или изменение ответственности будет не самой приятной задачей. К тому же вероятность ошибки все равно будет велика. Лучше определять роли доступа декларативно, таким образом будет легче управлять правами и сразу видно, что кому доступно. Легко вносить изменения и добавлять новые роли. Но обо всем по порядку.
PostSharp. Логирование
Продолжаем подробный разговор о аспекте OnMethodBoundary. Данный аспект применяется, когда у вас есть доступ к исходным кодам метода и вы хотите отслеживать события начала вызова метода, конец вызова, исключение и успешность завершения. Все это делается переопределением методов OnEntry, OnExit, OnException и OnSuccess соответственно.
Применение аспекта OnMethodBoundary рассмотрим на примере задач о разрешении или запрещении тех или иных действий, логирование интересующих нас действий, генерация служебного кода. Так же с помощью данного аспекта можно декларативно указывать запускать ли методы в отдельном потоке или нет, но это рассмотрим подробно и в деталях в другой статье. Сегодня на повестке дня логирование – это будет показано в одном приложении, исходный код которого можно свободно скачать и поиграться с ним.
Logging
Полезная функция, которая в состоянии подсказать где происходит ошибка и с каким набором данных, подсказать какие функции наиболее востребованы пользователями. Да мало ли еще какое применение можно найти для собранной детальной информации! =)
Будем основываться на приложении из прошлой статьи. У нас готов интерфейс для отображения происходящего в системе. Так что можно начинать.
PostSharp. Генерация кода
Сегодня я хочу остановиться поподробнее на аспекте OnMethodBoundary. Данный аспект применяется, когда у вас есть доступ к исходным кодам метода и вы хотите отслеживать события начала вызова метода, конец вызова, исключение и успешность завершения. Все это делается переопределением методов OnEntry, OnExit, OnException и OnSuccess соответственно.
Применение аспекта OnMethodBoundary рассмотрим на примере задач о разрешении или запрещении тех или иных действий, логирование интересующих нас действий, генерация служебного кода. Так же с помощью данного аспекта можно декларативно указывать запускать ли методы в отдельном потоке или нет, но это рассмотрим подробно и в деталях в другой статье. Сегодня на повестке дня безопасность, логирование и генерация кода – все это будет показано в одном приложении, исходный код которого можно свободно скачать и поиграться с ним.
Code Generation
На мой взгляд, больше всего «бесполезного» кода появляется на пользовательских формах и представлениях (UserControl) для WinForms. Необходимо подписывать почти каждый элемент на событие щелчка, изменения состояния элемента. Это куча кода, которую можно не писать совсем в большинстве случаев, если принять некоторые соглашения и строить весь интерфейс на биндинге. В конечном итоге такая практика поможет лучше понять идеологию WPF, если вы еще не перешли на нее. Да и поддерживать и тестировать такое подход, на мой взгляд, легче.
PostSharp. Альтернативы
Я тут подумал, что несправедливо было бы обойти стороной сравнение PostSharp и других продуктов предоставляющих АОП. Ниже будут рассмотрены особенности использования, плюсы и минусы различных подходов. Но не думайте что PostSharp является серебрянной пулей. =)
Можно почитать и википедию насчет АОП и фреймворков для .Net платформы. Я посмотрел несколько перечисленных там фреймворков лично и по документированности и простоте использования остановился на PostSharp.
Containers (Инверсия зависимостей)
Большинство фреймворков направленных на инверсию зависимостей включают в себя некоторые возможности аспектно-ориентированного программирования. Для большинства достаточно простых технических требований, таких как трейсинг и обработка исключений применяемых к сервисам приложения, их возможностей хватает. Но их нельзя применить для более сложных и комплексных аспектов, которые могут применяться так же к объектам пользовательского интерфейса или к доменным объектам.
Продукты: Spring.NET, Castle Windsor, Microsoft Unity
Плюсы:
- Вы уже используете фреймворк для инверсии зависимостей
- Аспекты могут быть настроены после сборки
- Некоторые аспекты (трейсинг и обработка исключений) могут быть уже реализованы в вашем фреймворке.
Минусы:
- Очень ограниченные возможности в плане АОП
- Ваши объекты должны создаваться с помощью контейнера предоставляемого фреймворком. Такой способ нельзя применить для элементов пользовательского интерфейса, и во многих случаях для доменных объектов тоже.
- Не работает со статическими, не публичными и/или не виртуальными методами. Так же не будет работать применение на поля, свойства и события классов.
- Нет, или же плохое инструментирование для Visual Studio
PostSharp. Обзор. Часть I
Прежде чем перейти непосредственно к теме повествования, необходимо сказать несколько слов о системных вещах.
Аспектно-Ориентированное программирование
Аспектно-ориентированное программирование (АОП) — парадигма программирования, основанная на идее разделения функциональности для улучшения разбиения программы на модули.
Существует достаточно много классов задач, решение которых невозможно в контексте ООП или же приведет к большой захламленности кода и связности модулей, что плохо. Например, логирование. Для того чтобы вести лог работы программы, необходимо в каждый метод поместить несколько служебных строчек вызова службы логирования, так же возможно придется ее передавать через входные параметры методов. Весь этот код не будет относиться к выполнению реальной задачи возложенной на метод, а только мозолить глаза. К тому же, сколько лишних строчек кода придется написать вручную!
Еще примером может служить авторизация и проверка прав доступа. По-хорошему, перед началом выполнения важных методов, надо каждый раз проверять, имеет ли текущий пользователь права на запуск указанного метода. Тут тоже может быть очень много мороки и кода.
В целом, любой сквозной код выпадает из возможностей ООП. АОП программирование, наоборот, предоставляет все средства для выделения «сквозного кода» в отдельные сущности, что существенно упрощает код как для тестирования, так и для использования.