LinFu AOP и LinFu IOC вводный экскурс часть первая

Зачастую при работе с БД (да и не только), особенно при использовании какого-нибудь ОРМ, возникает задача упрощения тех или иных процедур, которые приходится вызывать очень часто(к примеру открытие транзакции и её коммит, запросы с NOLOCK или банальный препроцессинг данных). Конечно все можно сделать по-старинке:

void Method(sometype somevalue)
{
   Preprocess(somevalue);
   OpenTransaction();
   // some stuff
   CommitTransaction();
}

Но «Шурик, это же не наш метод!»®. Потому мы пойдем дальше и воспользуемся более гуманными средствами а именно AOP и IOC (что это такое и с чем его едят вы можете почитать в интернете, потому не вижу смысла описывать это здесь)

До некоторых пор я использовал Unity, но что-то разонравилось мне оно и я решил его(её) сменить. Альтернативных вариантов много (Spring.Net AOP, Castle, PostSharp, Aspect#, LinFu и т.д.). Мой выбор пал на LinFu уж больно часто о нем упоминается на безграничных просторах интернета. В данном экскурсе я рассмотрю простой пример реализации транзакций при использовании NHibernate, ну и если будут многочисленные просьбы трудящихся продолжу в следующих.

Итак приступим.

Для начала скачиваем необходимые библиотеки Здесь

Открываем студию, создаем проект и добавляем необходимые ссылки на наши библиотеки (NHibernate, LinFu ну и что вы там еще собираетесь использовать), создаем объекты БД и маппинги к ним и DAO. Это я думаю вы и так умеете. Для удобства я создал базовый класс для DAO:

public class NHibernateDao
{  
        ISession _session;
        /// <summary>
        /// Gets NHibernate Session
        /// </summary>
        public ISession Session
        {
            get
            {
                return _session??this.DoGetSession();
            }
        }
        //some code stripped
}

И соответственно наследуем все DAO от него. И вот все готово можно приступать. дабы код смотрелся симпатичнее и гуманнее мы воспользуемся атрибутами. Сперва создаем базовый атрибут для перехвата:

public abstract class InterceptionAttribute: Attribute
{
     public abstract IInvokeWrapper GetInvokeWrapper();
     //или так кому как нравится.
     public abstract IInterceptor GetInterceptor();
}

IInvokeWrapper и IInterceptor — это интерфейсы линфу для перехвата вызываемых методов.

NB. Выбрать надо один из методов. не надо использовать оба — дальше поймете почему.

теперь собственно атрибут перехватчик:

    [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
    public class TransactionAttribute:InterceptionAttribute
    {

        public override IInvokeWrapper GetInvokeWrapper()
        {
            return new TransactionInvokeWrapper();
        }
        //или так кому как нравится.
        public override IInterceptor GetInterceptor()
        {
            return new TransactionInterceptor();
        }
    }

ну и сами перехватчики:

    public class TransactionInterceptor : IInterceptor
    {
        public object Intercept(IInvocationInfo info)
        {
            if (!(info.Target is NHibernateDao))
            {
                throw new InvalidOperationException("Transaction Attribute must be implemeted                                inside NHibernateDao class or its children");
            }
            (info.Target as NHibernateDao).Session.Transaction.Begin();

            var returnValue = info.TargetMethod.Invoke(info.Target, info.Arguments);

            try
            {
                (info.Target as NHibernateDao).Session.Transaction.Commit();
            }
            catch (DataException e)
            {
                (info.Target as NHibernateDao).Session.Transaction.Rollback();
                throw e;
            }
            return returnValue;
        }
    }

Или вот так если вы выбрали второй метод.

    public class TransactionInvokeWrapper : IInvokeWrapper
    {
        bool intercepted = true;
        public object DoInvoke(IInvocationInfo info)
        {
            return info.TargetMethod.Invoke(info.Target, info.Arguments);
        }

        public void BeforeInvoke(IInvocationInfo info)
        {
            (info.Target as NHibernateDao).Session.Transaction.Begin();
        }

        public void AfterInvoke(IInvocationInfo info, object returnValue)
        {
            try
            {
                (info.Target as NHibernateDao).Session.Transaction.Commit();
            }
            catch (DataException e)
            {
                (info.Target as NHibernateDao).Session.Transaction.Rollback();
                throw e;
            }
        }
    }

Эти два класса были упрощены: не надо привязываться к конкретному классу, лучше сделать получении Сессии через рефлексию. Я думаю тут комментарии излишни ибо названия методов говорят за себя.

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

Рейтинг
( Пока оценок нет )
Загрузка ...