AOP interceptors
12.06.2006
|
IT |
Добавил базовый перехватчик и несколько типовых аспектов на его базе: LoggingAspect, CacheAspect и CounterAspect. Хотел ещё сделать PermissionAspect, но там получается всё достаточно интимно и как сделать общее решение не понятно.
Использование.
LogginAspect:
CacheAspect кеширует результат вызова методов в зависимости от значения параметров. Кешируется возвращаемое значние и ref/out параметры.
CounterAspect собирает статистику по вызовам методов.
Использование.
LogginAspect:
public abstract class TestClass
{
// Лог конкретного метода.
//
[Log]
public virtual void Test(int p1)
{
}
// Логировать вызовы, выполняющиеся более 0.5 сек.
//
[Log("MinCallTime=500")]
public virtual void Test(int p1)
{
}
}
// Лог всех методов класса.
//
[Log]
public abstract class TestClass
{
public virtual void Test1(int p1)
{
}
// Отключить лог для данного метода
//
[NoLog]
public virtual void Test2(int p1)
{
}
}
void Test()
{
// Параметры, влияющие на все вызовы, исключая те, где эти параметры заданы явно.
//
LoggingAspect.LogParameters = true; // логировать значения параметров вызываемого метода. Умолчание - true.
LoggingAspect.LogExceptions = true; // логировать исключения. Умолчание - true.
LoggingAspect.MinCallTime = 1000; // логировать вызовы дольше 1 секунды. Умолчание - 0.
LoggingAspect.FileName = "log.txt"; // выводить в файл. Умолчание - null - Debug.WriteLine.
LoggingAspect.IsEnabled = false; // оключить лог. Умолчание - true.
TestClass t = TypeAccessor.CreateInstance<TestClass>();
t.Test(1);
}
CacheAspect кеширует результат вызова методов в зависимости от значения параметров. Кешируется возвращаемое значние и ref/out параметры.
public abstract class TestClass
{
// Кешировать результат вызова метода.
//
[Cache]
public virtual ArrayList Test(int p1)
{
return new ArrayList(p1);
}
}
// Кешировать результаты вызова всех методов класса на 1 секунду.
//
[Cache(1000)]
public abstract class TestClass
{
[NoCache]
public virtual void Test1(int p1)
{
}
}
void Test()
{
// Параметры, влияющие на все вызовы, исключая те, где эти параметры заданы явно.
//
CacheAspect.MaxCacheTime = 1000; // длительность кеширования. Умолчание - int.MaxValue.
CacheAspect.IsWeak = true; // использовать слабые ссылки. Умолчание - true.
CacheAspect.IsEnabled = false; // оключить кеширование. Умолчание - true.
TestClass t = TypeAccessor.CreateInstance<TestClass>();
t.Test(1);
}
CounterAspect собирает статистику по вызовам методов.
public abstract class TestClass
{
// Статистика вызовов метода.
//
[Counter]
public virtual ArrayList Test(int p1)
{
return new ArrayList(p1);
}
}
// Собирать статистику вызовов всех методов класса.
//
[Counter]
public abstract class TestClass
{
[NoCounter]
public virtual void Test1(int p1)
{
}
}
void Test()
{
// Параметры, влияющие на все вызовы, исключая те, где эти параметры заданы явно.
//
CounterAspect.IsEnabled = false; // оключить сбор статистики. Умолчание - true.
TestClass t = TypeAccessor.CreateInstance<TestClass>();
t.Test(1);
lock (CounterAspect.Counters.SyncRoot)
{
foreach (CounterAspect.Counter c in CounterAspect.Counters)
{
c.MethodInfo // метаданные метода
c.TotalTime // общее время выполнения всех завершённых вызовов
c.TotalCount // общее количество завершённых вызовов
c.CurrentCalls // текущие вызовы
// Здесь интерес могут представлять следующие поля
InterceptCallInfo ci = (InterceptCallInfo)c.CurrentCalls[0];
(IPrincipal)ci.Items["CurrentPrincipal"]; // кто вызвал метод
ci.BeginCallTime // когда
}
}
}
... << RSDN@Home 1.2.0 alpha rev. 0>>
12.06.2006 14 комментариев |
Хм... Вкусно! Как новый "орбит InterceptorAttribute".
Попробовал на живом проекте — сразу захотелось вынести настройку в конфиг.
А фиг вам! TypeExtension тут либо не работает, либо я не умею её готовить.
Вообще, вынос атрибутов во внешний файл идея сама по себе очень грамонтная. Например, можно вынести все запросы во внешний файл:
В данном примере можно задать [SqlQuery("SELECT * FROM Person")] во внешней xml-ке. Это очень круто, так как все запросы можно собрать в одном месте и иметь две версии — одну для production, одну для future release. Или одну для MSSQL а другую для Oracle. Жаль, что я не умею их готовить.
Скупая и устарелая информация не даёт возможности оценить размах и пустить в дело.
БП>Попробовал на живом проекте — сразу захотелось вынести настройку в конфиг.
БП>А фиг вам! TypeExtension тут либо не работает, либо я не умею её готовить.
Не работает. Надо делать что-то типа метадата провайдера. Но пока что-то в кучу не складывается.
IT>Надо делать что-то типа метадата провайдера.
Надо. В принципе, если не замахиваться на незамахиваемое, можно просто прикрутить всюду TypeExtension вместо Type.GetAttributes()
Только прийдётся добавить немного кода чтобы свести всё к простым типам.
В случае с InterceptorAttribute, например, можно вместо
заделать
Даже если всё задать через Xml не получится, всё равно овчинка стоит того, чтобы её уделали. Два вполне жизненных примера я привёл выше по теме.
IT>Добавил базовый перехватчик и несколько типовых аспектов на его базе: LoggingAspect, CacheAspect и CounterAspect. Хотел ещё сделать PermissionAspect, но там получается всё достаточно интимно и как сделать общее решение не понятно.
Классно!
IT>CacheAspect кеширует результат вызова методов в зависимости от значения параметров. Кешируется возвращаемое значние и ref/out параметры.
Было бы неплохо добавить возможность кешировать результаты вызовов методов не только в зависимости от параметров, но и в зависимости от экземпляра объекта. Кстати, как вообще можно получить экземпляр объекта в Interceptor'e?
IT>LogginAspect:
А зачем LoggingAspect переписывает файл при каждом логе, почему бы просто не добавлять в конец файла?
Как из перехватчика можно доступиться до самого объекта, метод которого перехвачен?
Спасибо
PZT>Как из перехватчика можно доступиться до самого объекта, метод которого перехвачен?
Забавно, но до сих пор ссылка на сам объект никому не понадобилась
Добавил свойство Object в InterceptCallInfo.
IT>Забавно, но до сих пор ссылка на сам объект никому не понадобилась
Двумя неделями раньше и двумя сообщениями выше — http://rsdn.ru/Forum/?mid=2089427&flat=0
Скоро, чувствую, ты напишешь, что забавно, что никому до сих пор не понадобился лог-файл
IT>>Забавно, но до сих пор ссылка на сам объект никому не понадобилась
A>Двумя неделями раньше и двумя сообщениями выше — http://rsdn.ru/Forum/?mid=2089427&flat=0
Пропустил
A>Скоро, чувствую, ты напишешь, что забавно, что никому до сих пор не понадобился лог-файл
А разве этого нет?
Либо глобально:
A>>Скоро, чувствую, ты напишешь, что забавно, что никому до сих пор не понадобился лог-файл
IT>А разве этого нет?
В другом сообщении, тоже двумя неделями раньше и тремя сообщениями выше — http://rsdn.ru/Forum/?mid=2089602&flat=0
IT>>А разве этого нет?
A>В другом сообщении, тоже двумя неделями раньше и тремя сообщениями выше — http://rsdn.ru/Forum/?mid=2089602&flat=0
И это пропустил
Это очень хорошо, но немного плохо
Как приделать внешний логгер?
A>Как приделать внешний логгер?
Реализацию MyLogOperation можно подсмотреть в LoggingAspect.cs.
A>>Как приделать внешний логгер?
IT>
IT>Реализацию MyLogOperation можно подсмотреть в LoggingAspect.cs.
Гуд. Будем пользовать.