AOP interceptors
От: IT Россия linq2db.com
Дата: 12.06.06 03:37
Оценка: 134 (8)
Добавил базовый перехватчик и несколько типовых аспектов на его базе: LoggingAspect, CacheAspect и CounterAspect. Хотел ещё сделать PermissionAspect, но там получается всё достаточно интимно и как сделать общее решение не понятно.

Использование.

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>>
Если нам не помогут, то мы тоже никого не пощадим.
Re: AOP interceptors
От: Блудов Павел Россия  
Дата: 13.06.06 03:56
Оценка: 3 (1)
Здравствуйте, IT!

Хм... Вкусно! Как новый "орбит InterceptorAttribute".

Попробовал на живом проекте — сразу захотелось вынести настройку в конфиг.
А фиг вам! TypeExtension тут либо не работает, либо я не умею её готовить.

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

        [TypeExtension(FileName="PersonAccessor.xml")]
        public abstract class PersonAccessor : DataAccessor
        {
            [SqlQuery("SELECT * FROM Person")]
            public abstract Person SelectAll();


В данном примере можно задать [SqlQuery("SELECT * FROM Person")] во внешней xml-ке. Это очень круто, так как все запросы можно собрать в одном месте и иметь две версии — одну для production, одну для future release. Или одну для MSSQL а другую для Oracle. Жаль, что я не умею их готовить.
Скупая и устарелая информация
Автор(ы): Игорь Ткачёв
Дата: 01.07.2003
В статье подробно рассматривается состав и способы применения пространства имён Rsdn.Framework.Data, представляющего собой высокоуровневую обёртку над ADO.NET.
не даёт возможности оценить размах и пустить в дело.
... << RSDN@Home 1.2.0 alpha rev. 642>>
Re[2]: AOP interceptors
От: IT Россия linq2db.com
Дата: 13.06.06 04:19
Оценка:
Здравствуйте, Блудов Павел, Вы писали:

БП>Попробовал на живом проекте — сразу захотелось вынести настройку в конфиг.

БП>А фиг вам! TypeExtension тут либо не работает, либо я не умею её готовить.

Не работает. Надо делать что-то типа метадата провайдера. Но пока что-то в кучу не складывается.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[3]: AOP interceptors
От: Блудов Павел Россия  
Дата: 13.06.06 09:59
Оценка:
Здравствуйте, IT, Вы писали:

IT>Надо делать что-то типа метадата провайдера.

Надо. В принципе, если не замахиваться на незамахиваемое, можно просто прикрутить всюду TypeExtension вместо Type.GetAttributes()
Только прийдётся добавить немного кода чтобы свести всё к простым типам.
В случае с InterceptorAttribute, например, можно вместо
    public class InterceptorAttribute
    {
        private readonly Type _interceptorType;
        public           Type  InterceptorType
        {
            get { return _interceptorType; }
        }
    }

заделать
    public class InterceptorAttribute
    {
        private readonly string _interceptorTypeName;     // Это в Xml задать не сложно
        private readonly Type _interceptorType;         // А это удобно задавать в аттрибуте
        public           Type  InterceptorType
        {
            get
            {
                return (null != _interceptorType) ? _interceptorType : _interceptorType = Type.GetType(_interceptorTypeName);
            }
        }
    }


Даже если всё задать через Xml не получится, всё равно овчинка стоит того, чтобы её уделали. Два вполне жизненных примера я привёл выше по теме.
... << RSDN@Home 1.2.0 alpha rev. 642>>
Re: AOP interceptors
От: Andy77 Ниоткуда  
Дата: 01.09.06 19:22
Оценка:
Здравствуйте, IT, Вы писали:

IT>Добавил базовый перехватчик и несколько типовых аспектов на его базе: LoggingAspect, CacheAspect и CounterAspect. Хотел ещё сделать PermissionAspect, но там получается всё достаточно интимно и как сделать общее решение не понятно.


Классно!

IT>CacheAspect кеширует результат вызова методов в зависимости от значения параметров. Кешируется возвращаемое значние и ref/out параметры.


Было бы неплохо добавить возможность кешировать результаты вызовов методов не только в зависимости от параметров, но и в зависимости от экземпляра объекта. Кстати, как вообще можно получить экземпляр объекта в Interceptor'e?
Re: AOP interceptors
От: Andy77 Ниоткуда  
Дата: 01.09.06 22:51
Оценка:
Здравствуйте, IT, Вы писали:

IT>LogginAspect:


А зачем LoggingAspect переписывает файл при каждом логе, почему бы просто не добавлять в конец файла?

private static void LogOutputInternal(string logText, string fileName)
{
    if (fileName == null || fileName.Length == 0)
        Debug.WriteLine(logText);
    else
        using (StreamWriter sw = new StreamWriter(fileName)) 
            sw.WriteLine(logText);
}
Re: AOP interceptors
От: PeterZT  
Дата: 18.09.06 08:52
Оценка:
Здравствуйте, IT

Как из перехватчика можно доступиться до самого объекта, метод которого перехвачен?

Спасибо
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Re[2]: AOP interceptors
От: IT Россия linq2db.com
Дата: 18.09.06 12:14
Оценка: 4 (1)
Здравствуйте, PeterZT, Вы писали:

PZT>Как из перехватчика можно доступиться до самого объекта, метод которого перехвачен?


Забавно, но до сих пор ссылка на сам объект никому не понадобилась

Добавил свойство Object в InterceptCallInfo.
Если нам не помогут, то мы тоже никого не пощадим.
Re[3]: AOP interceptors
От: Andy77 Ниоткуда  
Дата: 18.09.06 16:04
Оценка:
Здравствуйте, IT, Вы писали:

IT>Забавно, но до сих пор ссылка на сам объект никому не понадобилась


Двумя неделями раньше и двумя сообщениями выше — http://rsdn.ru/Forum/?mid=2089427&amp;flat=0
Автор: Andy77
Дата: 01.09.06


Скоро, чувствую, ты напишешь, что забавно, что никому до сих пор не понадобился лог-файл
Re[4]: AOP interceptors
От: IT Россия linq2db.com
Дата: 18.09.06 16:59
Оценка:
Здравствуйте, Andy77, Вы писали:

IT>>Забавно, но до сих пор ссылка на сам объект никому не понадобилась

A>Двумя неделями раньше и двумя сообщениями выше — http://rsdn.ru/Forum/?mid=2089427&amp;flat=0
Автор: Andy77
Дата: 01.09.06


Пропустил

A>Скоро, чувствую, ты напишешь, что забавно, что никому до сих пор не понадобился лог-файл


А разве этого нет?

[Log(FileName="...")]


Либо глобально:

LoggingAspect.FileName = "...";
Если нам не помогут, то мы тоже никого не пощадим.
Re[5]: AOP interceptors
От: Andy77 Ниоткуда  
Дата: 18.09.06 17:34
Оценка:
Здравствуйте, IT, Вы писали:

A>>Скоро, чувствую, ты напишешь, что забавно, что никому до сих пор не понадобился лог-файл


IT>А разве этого нет?


В другом сообщении, тоже двумя неделями раньше и тремя сообщениями выше — http://rsdn.ru/Forum/?mid=2089602&amp;flat=0
Автор: Andy77
Дата: 02.09.06
Re[6]: AOP interceptors
От: IT Россия linq2db.com
Дата: 18.09.06 23:55
Оценка:
Здравствуйте, Andy77, Вы писали:

IT>>А разве этого нет?


A>В другом сообщении, тоже двумя неделями раньше и тремя сообщениями выше — http://rsdn.ru/Forum/?mid=2089602&amp;flat=0
Автор: Andy77
Дата: 02.09.06


И это пропустил
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re: AOP interceptors
От: adontz Грузия http://adontz.wordpress.com/
Дата: 21.09.06 12:17
Оценка:
Здравствуйте, IT, Вы писали:

Это очень хорошо, но немного плохо

Как приделать внешний логгер?
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[2]: AOP interceptors
От: IT Россия linq2db.com
Дата: 21.09.06 12:29
Оценка: 57 (2)
Здравствуйте, adontz, Вы писали:

A>Как приделать внешний логгер?


LoggingAspect.LogOperation = MyLogOperation;

private static void MyLogOperation(InterceptCallInfo info)
{
  ....
}

Реализацию MyLogOperation можно подсмотреть в LoggingAspect.cs.
Если нам не помогут, то мы тоже никого не пощадим.
Re[3]: AOP interceptors
От: adontz Грузия http://adontz.wordpress.com/
Дата: 21.09.06 13:20
Оценка:
Здравствуйте, IT, Вы писали:

A>>Как приделать внешний логгер?


IT>
IT>LoggingAspect.LogOperation = MyLogOperation;

IT>private static void MyLogOperation(InterceptCallInfo info)
IT>{
IT>  ....
IT>}
IT>

IT>Реализацию MyLogOperation можно подсмотреть в LoggingAspect.cs.

Гуд. Будем пользовать.
A journey of a thousand miles must begin with a single step © Lau Tsu
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.