Диссертация (1148251), страница 22
Текст из файла (страница 22)
В неё входятследующие функциональные блоки:1) Caching Application Block для поддержки кэширования;2) Cryptography Application Block для поддержки шифрования;3) Data Access Application Block для поддержки работы с базами данных;4) Exception Handling Application Block для реализации стратегийобработки исключений;5) Logging Application Block для поддержки протоколирования;6) Security Application Block для поддержки авторизации и безопасностиприложений;7) Validation Application Block для поддержки механизмов валидацииданных бизнес-объектов.122В 2011 году компания Microsoft выпустила расширение Enterprise LibraryIntegration Pack for Microsoft Azure [63], которое содержит функциональные блокидляуправленияпроизводительностью(AutoscalingApplicationBlock)иограничения функциональности под нагрузкой (Transient Fault Handling Block).Программист может реализовать ту или иную “сквозную” функциональность,если в исходном коде своего проекта вызовет методы из набора классовсоответствующего функционального блока.
С точки зрения АОП очевидно, чтоместоположение этих вызовов в исходном коде целевого приложения являетсясовокупностью точек внедрения для действий соответствующего аспекта.Для практического ознакомления с EL Integration Pack for Windows Azureкомпания Microsoft предлагает серию лабораторных работ (Hands-on Labs).Программисту предоставляется исходный проект и методические указания по егопошаговому изменению. Полученный результат можно сравнить с эталоннымконечнымпроектом,вкоторомтеперьзадействуетсятотилиинойфункциональный блок EL Integration Pack for Windows Azure. Если на основе этихметодических указаний составить аспект и применить его с помощью Aspect.NETкначальномупроекту,торезультирующаясборкабудетобладатьфункциональностью соответствующего эталонного проекта, но без модификациикода исходного проекта.6.2 Logging Application BlockРассмотрим упражнение “Hands-on Lab 1: Using the Logging ApplicationBlock with Windows Azure Storage”, где путем добавления ссылок на сборки ELпроизводится подключение функционального блока логгирования к исходномупроекту, а затем вызов его метода для передачи сообщения в облачное хранилищедиагностическойинформацииWAD.Этодаетвозможностьнастраиватьпараметры сбора и хранения отладочных сообщений через графическийинтерфейс Logging Application Block, либо через его конфигурационные файлы.123//Веб-роль, на странице которой тестируется Logging Application Blockpublic partial class Default : System.Web.UI.Page{//Сообщение отсылается в обработчике щелчка мыши по кнопке страницыprotected void LogButton_Click(object sender, EventArgs e) {Microsoft.Practices.EnterpriseLibrary.Logging.Logger.Write("Message from the Logging Application Block");}}ЛИСТИНГ 52.
ИСХОДНЫЙ КОД ПРОТОКОЛИРОВАНИЯ ДЕЙСТВИЙИтак, задача заключается в том, чтобы перенести все зависимости от EL ивызовы методов протоколирования в отдельный проект с аспектом. Применивзатем с помощью Aspect.NET данный аспект к исходному проекту, мы получимего бесшовную интеграцию с Logging Application Block.Традиционно в Aspect.NET подобные задачи решаются размещением кодапротоколирования в действии аспекта и вставкой его перед, после, или вместовызова целевого метода в исходном проекте. В нашем случае целевой метод — этообработчик события щелчка мыши LogButton_Click() класса веб-страницыDefault, причем созданием объекта этого класса и отправкой ему событийзанимается среда ASP.NET и сервер IIS. Это означает, что код вызова нашегоцелевого метода располагается вне сборки исходного проекта и недоступенAspect.NET.
Как продемонстрированно в разделе 3.3, в таких случаях необходимоиспользоватьподменуцелевогоклассачерезаспектногоReplaceBaseClass://Проект с замещающим аспектным наследником[AspectDotNet.ReplaceBaseClass]public class AspectClass : Default {protected void LogButton_Click(object sender, EventArgs e) {Microsoft.Practices.EnterpriseLibrary.Logging.Logger.Write("Message from the Logging Application Block");base.LogButton_Click(sender, e);}}//Исходный проект, после отделения зависимости от Logging Application Blockpublic partial class Default : System.Web.UI.Page{protected void LogButton_Click(object sender, EventArgs e) {}}ЛИСТИНГ 53. ПРОТОКОЛИРОВАНИЕ, ВЫНЕСЕНОЕ В АСПЕКТнаследника1246.3 Autoscaling Application BlockРассмотрим теперь “Hands-on Lab 6: Implementing Throttling Behavior”, гдеиллюстрируется ограничение функциональности под нагрузкой с использованиемсервисов функционального блока Autoscaling Application Block.
Отдельныйкомпонент Autoscaler занимается мониторингом диагностической информации и,в зависимости от текущей нагрузки на облако, устанавливает свойствоThrottlingMode в файле конфигурации исходного проекта. В зависимости отзначения этого свойства какие-то из методов класса веб-страницы могут изменятьсвое поведение://Веб-роль, на странице которой тестируется Autoscaling Application Blockpublic partial class Default : System.Web.UI.Page{protected override void OnPreRenderComplete(EventArgs e) {base.OnPreRenderComplete(e);string throttlingMode = RoleEnvironment.GetConfigurationSettingValue("ThrottlingMode");switch (throttlingMode){case "HighActivity":this.ThrottlingLabel.Text = "Работа при высокой активности…";break;default:this.ThrottlingLabel.Text = "Работа при обычной активности…";this.DoSomeUsualWork();break;}}}private void DoSomeUsualWork() {/*…*/ }ЛИСТИНГ 54.
ИСХОДНЫЙ КОД ПОВЕДЕНИЯ ПРИ РАЗЛИЧНЫХ УРОВНЯХ НАГРУЗКИДанный метод можно перенести в аспект и тогда целевой класс будетсконцентрирован только на решении своей задачи, в то время как компонентAutoscaler и бесшовная интеграция с аспектом обеспечит реакцию наповышенную нагрузку. Задачу можно было бы решить аналогично предыдущемупримеру, но здесь есть препятствие в виде вызова закрытого в целевом классеметода DoSomeUsualWork().
Для того, чтобы он стал доступным замещающемунаследнику, компоновщик аспектов мог бы принудительно сделать этот методзащищенным.Однакоэтонарушитинкапсуляциюцелевогокласса,иединственный способ сохранить её — использовать рефлексию .NET. Закрытые125члены целевого класса становятся полями его аспектного наследника, которыеинициализируются в конструкторе. Также предположим, что в замещающемнаследнике целевого класса нам понадобится вызвать метод OnPreRenderCompleteследующего по иерархии базового класса System.Web.UI.Page. Защищенные иоткрытые методы целевого класса используются в его замещающем аспектномнаследнике без ограничений. Итоговый аспект представлен ниже:using System.Reflection;[AspectDotNet.ReplaceBaseClass]public class AspectClass : _Default {MethodInfo DoSomeUsualWork, PageOnPreRenderComplete;public AspectClass() {Type BaseType = this.GetType().BaseType;//Получение ссылки на закрытый метод целевого класса _DefaultDoSomeUsualWork = BaseType.GetMethod("DoSomeUsualWork",BindingFlags.NonPublic | BindingFlags.Instance);//Ссылка на метод базового класса System.Web.UI.PagePageOnPreRenderComplete = base.GetType().BaseType.GetMethod("OnPreRenderComplete", BindingFlags.NonPublic |BindingFlags.Instance);}protected override void OnPreRenderComplete(EventArgs e) {//Вызываем метод базового класса System.Web.UI.PagePageOnPreRenderComplete.Invoke(this, new object [] { e });}}string throttlingMode = RoleEnvironment.GetConfigurationSettingValue("ThrottlingMode");switch (throttlingMode) {case "HighActivity"://Использование в аспекте члена целевого класса _Defaultthis.ThrottlingLabel.Text = "Работа при высокойактивности…";break;default:this.ThrottlingLabel.Text = "Работа при обычнойактивности…";//Вызов закрытого члена целевого класса _DefaultDoSomeUsualWork.Invoke(this, null);break;}ЛИСТИНГ 55.
КОД ИЗМЕНЕНИЯ ПОВЕДЕНИЯ ПРИ РАЗЛИЧНЫХ УРОВНЯХ НАГРУЗКИ, ВЫНЕСЕНЫЙ В АСПЕКТ6.4 Transient Fault Handling Application BlockСледующий пример бесшовной интеграции основан на примере “Hands-onLab 11: Transient Fault Handling”. Здесь задача заключается в том, чтобы добавить126в целевой код работы с базой данных стратегию обработки исключительныхситуаций. Сама стратегия отделена от кода, работающего с базой данных, иконфигурируется средствами EL. Например, для любого запроса к базе данныхможно составить стратегию вида: попытаться совершить 4 последовательныхзапроса, если каждый из предыдущих совершается неудачно. При этом междувторым и третьим запросом должна быть пауза в 5 сек.
Исходный код целевогокласса приведен ниже:public class Main : Form {private void ExecuteQueryButton_Click(object sender, EventArgs e) {//…try {using (var connection = newSqlConnection(ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString)) {connection.Open();var command = new SqlCommand("dbo.GetProductDetails",connection){ CommandType = CommandType.StoredProcedure };// …Заполнение параметров command…using (var reader = command.ExecuteReader()) {while (reader.Read()) {//…Обрабатываем результат успешного запроса}}}}catch (Exception ex) {//…}}}ЛИСТИНГ 56. ИСХОДНЫЙ КОД ОБРАБОТКИ ИСКЛЮЧЕНИЙ ПРИ СВЯЗИ С БДЗапроскбазеданныхпроизводитсяспомощьювызоваметодаSqlCommand.ExecuteReader(), который может выбросить исключение при сбоесоединения с базой данных.
Чтобы применить к нему стратегию обработкиисключительных ситуаций, необходимо выполнить данный блок в рамках методаExecuteAction() класса Microsoft.Practices.TransientFaultHandling.RetryPolicy<T>,где T — класс, реализующий стратегию. Получить объект этого класса можночерез специальный менеджер TransientFaultHandling.RetryManager, которыйдолжен быть инициализирован библиотекой EL и передан в конструкторецелевого класса. Для этого требуется %instead-действием заменить при запуске127приложения Application.Run(Main) на создание объекта нашего замещающегонаследника с помощью средств EL:class ChangeRunAspect : AspectDotNet.Aspect{[AspectDotNet.AspectAction("%instead %call *.Application.Run")]static public void ReplaceAction() {Application.Run(EnterpriseLibraryContainer.Current.GetInstance<AspectMain>());}}ЛИСТИНГ 57.