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)
