AOP With Unity 2.0

by Daniel Lins Leite 12. March 2010 08:55

part 2 - http://www.machinaaurum.com.br/blog/post/AOP-With-Unity-20-2.aspx
part 3 - http://www.machinaaurum.com.br/blog/post/AOP-With-Unity-20-3.aspx

In this post i want to show how one can use a Inversion of Control ( IoC ) container to make some kind of Aspect-oriented programming ( AOP ). I will start with a simple example, then use Unity 2.0 to construct my types, then make a little modification to only allows administrator to run my code, then use a Proxy Generator to ease my task and finally use Unity and the Proxy generator to allow a easy AOP.

Let us start with a simple Account class.

     class Account
    {
        public Account(float quantity)
        {
            Quantity = quantity;
        }

        public float Quantity { get; set; }
    }

I want to be able to make some move operations, move some money from one account to another. So, i will create an interface and a concrete class.

    interface IMoveOperation
    {
        void Move(Account sourceAccount, Account destinationAccount, float quantity);
    }

    class MoveOperation : IMoveOperation
    {
        #region IAccountManager Members

        public void Move(Account sourceAccount, Account destinationAccount, float quantity)
        {
            sourceAccount.Quantity -= quantity;
            destinationAccount.Quantity += quantity;
        }

        #endregion
    }

And the code that use the Account class and the MoveOperation is...

    class Program
    {
        static void Main(string[] args)
        {
            Account a = new Account(100.0f);
            Account b = new Account(50.0f);

            Print(a, b);

            IMoveOperation operation = new MoveOperation();
            operation.Move(a, b, 10.0f);

            Print(a, b);

            Console.ReadKey();
        }

        private static void Print(Account a, Account b)
        {
            Console.WriteLine("A:{0}", a.Quantity);
            Console.WriteLine("B:{0}", b.Quantity);
        }
    }

Running this code give me the following result... 

Look fine... let us use the Unity to create the MoveOperation.

        static void Main(string[] args)
        {
            Account a = new Account(100.0f);
            Account b = new Account(50.0f);

            IUnityContainer container = new UnityContainer();
            container.RegisterType<IMoveOperation, MoveOperation>();

            Print(a, b);

            IMoveOperation operation = container.Resolve<IMoveOperation>();
            operation.Move(a, b, 10.0f);

            Print(a, b);

            Console.ReadKey();
        }

Let us run again to make sure that everything is still working. 

Now, i want that only the system administrator can run this MoveOperation. I will use the CurrentPrincipal of the .NET framework. For now the code does not need to run, a SecurityException will be the expected result. The secutiry will not be inserted in the MoveOperation class. I will use the Decorator Pattern that will authorize the user and call the MoveOperation class.

    class MoveOperationAuthorization : IMoveOperation
    {
        IMoveOperation Operation { get; set; }

        public MoveOperationAuthorization(IMoveOperation operation)
        {
            Operation = operation;
        }

        #region IMoveOperation Members

        public void Move(Account sourceAccount, Account destinationAccount, float quantity)
        {
            if (System.Threading.Thread.CurrentPrincipal.IsInRole("Administrator"))
            {
                Operation.Move(sourceAccount, destinationAccount, quantity);
            }
            else
            {
                throw new SecurityException();
            }
        }

        #endregion
    }

And the construction of the IMoveOperation interface will be changed in the Unity to...

            IUnityContainer container = new UnityContainer();
            container.RegisterType<IMoveOperation>( new InjectionFactory ( (u) =>
                {
                    return new MoveOperationAuthorization ( new MoveOperation() );
                }));

and the result is... 

Ok, but this solution needs a lot of infrastructure code. Every class need a decorator and the Unity configuration. I will use a Proxy Generator to generate the proxy classes and use it to make this operation a little easier.

The Proxy Generator can be downloaded here. It´s a TT to Visual Studio 2010 that generates a proxy to every interface in the project. The only thing i have to do is to insert the TT in the project and run it ( Righ-Click and "Run Custom Tool..." ). 

After the execution the TT creates an associated .CS file. This file have all the generated Proxies.

And i can use the proxy directly in the Unity configuration.

            IUnityContainer container = new UnityContainer();
            container.RegisterType<IMoveOperation>( new InjectionFactory ( (u) =>
                {
                    var proxy = new ProxyIMoveOperation(new MoveOperation());
                    proxy.Move((op, source, dest, quantity) =>
                        {
                            if (System.Threading.Thread.CurrentPrincipal.IsInRole("Administrator") == false)
                            {
                                throw new SecurityException();
                            }
                        });
                    return proxy;
                })); 

Running this code and i have the SecurityException again.

But i can not say that this code is better than the last one. I will use now a extension to the Unity (download link at the bottom) that allows a better injection of the authorization in the MoveOperation class. First i have to implement the authorization code as method injection.

    class OnlyAdministratorMethodInjection : IMethodInjection
    {
        #region IMethodInjection Members

        public void Before()
        {
            if (System.Threading.Thread.CurrentPrincipal.IsInRole("Administrator") == false)
            {
                throw new SecurityException();
            }
        }

        #endregion
    }

 

This code is totally generic. I am not saying that it will call the MoveOperation class, this authorization code can be used in any method that need to be authorized. After this i have to make a modification in the Move method.

        [Inject(Order = 1, Injection = typeof(OnlyAdministratorMethodInjection))]
        public void Move(Account sourceAccount, Account destinationAccount, float quantity)
        {

With this i am saying that the OnlyAdministratorMethodInjection will be the first method to be called before the Move method starts. And the final step is to configure the Unity Extension.

        static void Main(string[] args)
        {
            Account a = new Account(100.0f);
            Account b = new Account(50.0f);

            IUnityContainer container = new UnityContainer();
            container.AddNewExtension<UnityAopExtension>();
            container.Configure<UnityAopExtension>().RegisterType<IMoveOperation, MoveOperation>();
          
            Print(a, b);

            IMoveOperation operation = container.Resolve<ProxyIMoveOperation>();
            operation.Move(a, b, 10.0f);

            Print(a, b);

            Console.ReadKey();
        }

Now i can say that the code looks much better. Running this code we have...

Important: This is only experimental code.

MachinaAurum.Unity.Aspect.dll.7z (4.31 kb)

kick it on DotNetKicks.com

Tags: , , , , ,

Development

Comments (3) -

Denis Gladkikh Russia
3/29/2010 2:20:19 AM #

Thanks, this is really interesting. Tomorrow want to find some really easy way to use AOP in my project for logging/ authorization and input parameter check and you save me a lot of time.

Dima Pasko Ukraine
3/31/2010 8:02:47 PM #

Cool!

Are you going to open sources of this project (codeplex or github)?
(MachinaAurum.Unity.Aspect)

Daniel Lins Leite Brazil
4/1/2010 1:53:51 AM #

Yes, i am planning to put it in CodePlex with the others projects that i have in mind.

Pingbacks and trackbacks (5)+


RecentComments

Comment RSS