msdnmagazine.com February 2014 63
You simply create the new class, passing an instance of the old
class as a parameter for its constructor. When you execute the
program, you can see it has the logging, as shown in Figure 6.
You might be thinking: “OK, the idea is good, but it’s a lot of work: I
have to implement all the classes and add the aspect to all the methods.
Th at will be diffi cult to maintain. Is there another way to do it?” With
the .NET Framework, you can use refl ection to get all methods and
execute them. Th e base class library (BCL) even has the RealProxy
class (bit.ly/18MfxWo) that does the implementation for you.
Creating a Dynamic Proxy with RealProxy
Th e RealProxy class gives you basic functionality for proxies. It’s
an abstract class that must be inherited by overriding its Invoke
method and adding new functionality. Th is class is in the name-
space System.Runtime.Remoting.Proxies. To create a dynamic
proxy, you use code similar to Figure 7.
In the constructor of the class, you must call the constructor of
the base class, passing the type of the class to be decorated. Th en
you must override the Invoke method that receives an IMessage
parameter. It contains a dictionary with all the parameters passed for
the method. Th e IMessage parameter is typecast to an IMethod-
CallMessage, so you can extract the parameter MethodBase (which
has the MethodInfo type).
Th e next steps are to add the aspect you want before calling the
method, call the original method with methodInfo.Invoke and
then add the aspect aft er the call.
You can’t call your proxy directly, because DynamicProxy
an IRepository
IRepository<Customer> customerRepository =
new DynamicProxy<IRepository<Customer>>(
new Repository<Customer>());
To use the decorated repository, you must use the GetTrans-
parentProxy method, which will return an instance of
IRepository
will go through the proxy’s Invoke method. To ease this process,
you can create a Factory class to create the proxy and return the
instance for the repository:
pu blic class RepositoryFactory
{
public static IRepository<T> Create<T>()
{
var repository = new Repository<T>();
var dynamicProxy = new DynamicProxy<IRepository<T>>(repository);
return dynamicProxy.GetTransparentProxy() as IRepository<T>;
}
}
Th at way, the main program will be similar to Figure 8.
When you execute this program, you get a similar result as
before, as shown in Figure 9.
As you can see, you’ve created a dynamic proxy that allows add-
ing aspects to the code, with no need to repeat it. If you wanted to
static void Main(string[] args)
{
Console.WriteLine("***\r\n Begin program - logging with dynamic proxy\r\n");
// IRepository<Customer> customerRepository =
// new Repository<Customer>();
// IRepository<Customer> customerRepository =
// new LoggerRepository<Customer>(new Repository<Customer>());
IRepository<Customer> customerRepository =
RepositoryFactory.Create<Customer>();
var customer = new Customer
{
Id = 1,
Name = "Customer 1",
Address = "Address 1"
;
customerRepository.Add(customer);
customerRepository.Update(customer);
customerRepository.Delete(customer);
Console.WriteLine("\r\nEnd program - logging with dynamic proxy\r\n***");
Console.ReadLine();
}
Figure 8 The Main Program with a Dynamic Proxy
Figure 9 Program Execution with Dynamic Proxy
class AuthenticationProxy<T> : RealProxy
{
private readonly T _decorated;
public AuthenticationProxy(T decorated)
: base(typeof(T))
{
_decorated = decorated;
}
private void Log(string msg, object arg = null)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(msg, arg);
Console.ResetColor();
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase as MethodInfo;
if (Thread.CurrentPrincipal.IsInRole("ADMIN"))
{
try
{
Log("User authenticated - You can execute '{0}' ",
methodCall.MethodName);
var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
return new ReturnMessage(result, null, 0,
methodCall.LogicalCallContext, methodCall);
}
catch (Exception e)
{
Log(string.Format(
"User authenticated - Exception {0} executing '{1}'", e),
methodCall.MethodName);
return new ReturnMessage(e, methodCall);
}
}
Log("User not authenticated - You can't execute '{0}' ",
methodCall.MethodName);
return new ReturnMessage(null, null, 0,
methodCall.LogicalCallContext, methodCall);
}
}
Figure 1 0 An Authentication Proxy