msdnmagazine.com February 2014 65
Now you need to make the change in only one place, but you still
need to change the class every time you want to change the fi lter.
One solution to this would be to expose the fi lter as a class property,
so you can assign the responsibility of creating a fi lter to the caller.
You can create a Filter property of type Predicate
and use it to fi lter the data, as shown in Figure 15.
Th e Filter property is initialized with Filter = m => true. Th at
means there’s no fi lter active. When assigning the Filter property,
the program verifies if the value is null and, if so, it resets the
filter. In the Invoke method execution, the program checks the
fi lter result and, if true, it applies the aspect. Now the proxy cre-
ation in the factory class looks like this:
public class RepositoryFactory
{
public static IRepository<T> Create<T>()
{
var repository = new Repository<T>();
var dynamicProxy = new DynamicProxy<IRepository<T>>(repository)
{
Filter = m => !m.Name.StartsWith("Get")
};
return dynamicProxy.GetTransparentProxy() as IRepository<T>;
}
}
}
Th e responsibility of creating the fi lter has been transferred to
the factory. When you run the program, you should get something
like Figure 16.
Notice in Figure 16 that the last two methods, GetAll and
GetById (represented by “Getting entities” and “Getting entity 1”)
don’t have logging around them. You can enhance the class even
further by exposing the aspects as events. Th at way, you don’t have
to change the class every time you want to change the aspect. Th is
is shown in Figure 17.
In Figure 17, three events, BeforeExecute, AfterExecute and
ErrorExecuting, are called by the methods OnBeforeExecute,
OnAft erExecute and OnErrorExecuting. Th ese methods verify whether
the event handler is defi ned and, if it is, they check if the called
method passes the fi lter. If so, they call the event handler that applies
the aspect. Th e factory class now becomes something like Figure 18.
Now you have a flexible proxy class, and you can choose the
aspects to apply before executing, aft er executing or when there’s
an error, and only for selected methods. With that, you can apply
many aspects in your code with no repetition, in a simple way.
Not a Replacement
With AOP you can add code to all layers of your application in a
centralized way, with no need to repeat code. I showed how to cre-
ate a generic dynamic proxy based on the Decorator design pattern
that applies aspects to your classes using events and a predicate to
fi lter the functions you want.
As you can see, the RealProxy class is a fl exible class and gives
you full control of the code, with no external dependencies. How-
Figure 1 6 Output with a Filtered Proxy
Figure 15 A Filtering Proxy
class DynamicProxy<T> : RealProxy
{
private readonly T _decorated;
private Predicate<MethodInfo> _filter;
public DynamicProxy(T decorated)
: base(typeof(T))
{
_decorated = decorated;
_filter = m => true;
}
public Predicate<MethodInfo> Filter
{
get { return _filter; }
set
{
if (value == null)
_filter = m => true;
else
_filter = value;
}
}
private void Log(string msg, object arg = null)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(msg, arg);
Console.ResetColor();
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase as MethodInfo;
if (_filter(methodInfo))
Log("In Dynamic Proxy - Before executing '{0}'",
methodCall.MethodName);
try
{
var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
if (_filter(methodInfo))
Log("In Dynamic Proxy - After executing '{0}' ",
methodCall.MethodName);
return new ReturnMessage(result, null, 0,
methodCall.LogicalCallContext, methodCall);
}
catch (Exception e)
{
if (_filter(methodInfo))
Log(string.Format(
"In Dynamic Proxy- Exception {0} executing '{1}'", e),
methodCall.MethodName);
return new ReturnMessage(e, methodCall);
}
}
}