2

I'm working (maintaining) on a dll assembly that acts as a Data Access Layer, there are many methods that requires transaction handling, many other do not, it's a currently "functional" dll, without any transaction handling method, I need to add it, so I'm looking for an easy way to add a transaction handler.

I'm wondering if is it possible to use AOP to create a decorator that I can add to the methods that requires a transaction.

I would like to have something like this:

[Transaction]
void MyDbMethod()
{
  //DoSomething
  myContext.SaveChanges();  
}

For the EF model definition I'm using Code First, the current project uses Unity framework for some other DI tasks, can that framework be used for this?

Anon Dev
  • 1,361
  • 3
  • 14
  • 29
  • Possibly look into this http://stackoverflow.com/questions/13211261/using-attributes-to-call-methods then you can check `System.Transactions.Transaction.Current != null` and decide to continue or not. – Wurd Sep 15 '16 at 16:01

2 Answers2

2

If someone faces this same issue, I did not found any "by hand" solution, instead I used the PostSharp library and its OnMethodBoundaryAspect class, but be careful, at this moment the free/express license has limitations about the amount of classes where you can use it, so read carefully its limitations.

using System.Transactions;
using PostSharp.Aspects;
using PostSharp.Serialization;

namespace MyProject
{
    [PSerializable]
    public class Transaction : OnMethodBoundaryAspect
    {
        public Transaction()
        {
            //Required if the decorated method is async
            ApplyToStateMachine = true;
        }

        public override void OnEntry(MethodExecutionArgs args)
        {
            //TransactionScopeAsyncFlowOption.Enabled => Required if the decorated method is async
            var transactionScope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled);
            args.MethodExecutionTag = transactionScope;
        }

        public override void OnSuccess(MethodExecutionArgs args)
        {
            var transactionScope = (TransactionScope)args.MethodExecutionTag;
            transactionScope.Complete();
        }

        public override void OnExit(MethodExecutionArgs args)
        {
            var transactionScope = (TransactionScope)args.MethodExecutionTag;
            transactionScope.Dispose();
        }
    }
}
Anon Dev
  • 1,361
  • 3
  • 14
  • 29
2

You can do it using NConcern .NET AOP Framework.

This is an open source runtime AOP framework on which I actively work.

public class DataAccessLayer : IAspect
{
    public IEnumerable<IAdvice> Advise(MethodInfo method)
    {
        //define how to rewrite method
        yield return Advice.Basic.Arround(invoke =>
        {
            using (var transaction = new TransactionScope(...))
            {
                invoke(); //invoke original code
                transaction.Complete();
            }
        });
    }
}

Your business

public class MyBusiness
{
    [Transaction]
    void MyDbMethod()
    {
    }
}

Attach transaction scope aspect to you business

Aspect.Weave<DataAccessLayer>(method => method.IsDefined(typeof(TransactionAttribute), true);
Tony THONG
  • 772
  • 5
  • 11
  • Didn't know about this project, seems like quite a nice "starter" alternative to postsharp and fody. The page mentions that it performs the weaving at runtime; how does this affect the performance versus compile-time weaving or fiddling with the binaries with Cecil? – easuter Dec 12 '16 at 09:26
  • 1
    Performance is mainly altered in "fire time" not in nominal time. In my own benchmark, it can be faster than PostSharp in nominal use. – Tony THONG Dec 12 '16 at 09:29
  • Good to hear; I've sort of been looking for something just like this since Postsharp is prohibitively expensive and Fody's extensions are of very inconsistent quality. Thanks for taking the time to post here! :) – easuter Dec 12 '16 at 09:32
  • 1
    You're welcome, don't hesitate to give me a feedback to improve the Framework if needed or simply if something is not clear... like I said, i stay really active on this projet. – Tony THONG Dec 12 '16 at 09:39