64 msdn magazine Aspect-Oriented Programming
add a new aspect, you’d only need to create a new class, inherit from
RealProxy and use it to decorate the fi rst proxy.
If your boss comes back to you and asks you to add authoriza-
tion to the code, so only administrators can access the repository,
you could create a new proxy as shown in Figure 10.
Th e repository factory must be changed to call both proxies, as
shown in Figure 11.
When you change the main program to Figure 12 and run it,
you’ll get the output shown in Figure 13.
Th e program executes the repository methods twice. Th e fi rst
time, it runs as an admin user and the methods are called. Th e sec-
ond time, it runs as a normal user and the methods are skipped.
That’s much easier, isn’t it? Note that the factory returns an
instance of IRepository
using the decorated version. Th is respects the Liskov Substitution
Principle, which says that if S is a subtype of T, then objects of type
T may be replaced with objects of type S. In this case, by using an
IRepository
implements this interface with no change in the program.
Filtering Functions
Until now, there was no filtering in the functions; the aspect is
applied to every class method that’s called. Often this isn’t the
desired behavior. For example, you might not want to log the
retrieval methods (GetAll and GetById). One way to accomplish
this is to fi lter the aspect by name, as in Figure 14.
Th e program checks if the method starts with “Get.” If it does, the
program doesn’t apply the aspect. Th is works, but the fi ltering code is
repeated three times. Besides that, the fi lter is inside the proxy, which
will make you change the class every time you want to change the
proxy. You can improve this by creating an IsValidMethod predicate:
private static bool IsValidMethod(MethodInfo methodInfo)
{
return !methodInfo.Name.StartsWith("Get");
}
static void Main(string[] args)
{
Console.WriteLine(
"***\r\n Begin program - logging and authentication\r\n");
Console.WriteLine("\r\nRunning as admin");
Thread.CurrentPrincipal =
new GenericPrincipal(new GenericIdentity("Administrator"),
new[] { "ADMIN" });
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\nRunning as user");
Thread.CurrentPrincipal =
new GenericPrincipal(new GenericIdentity("NormalUser"),
new string[] { });
customerRepository.Add(customer);
customerRepository.Update(customer);
customerRepository.Delete(customer);
Console.WriteLine(
"\r\nEnd program - logging and authentication\r\n***");
Console.ReadLine();
}
Figure 12 The Main Program Calling
the Repository with Two Users
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase as MethodInfo;
if (!methodInfo.Name.StartsWith("Get"))
Log("In Dynamic Proxy - Before executing '{0}'",
methodCall.MethodName);
try
{
var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
if (!methodInfo.Name.StartsWith("Get"))
Log("In Dynamic Proxy - After executing '{0}' ",
methodCall.MethodName);
return new ReturnMessage(result, null, 0,
methodCall.LogicalCallContext, methodCall);
}
catch (Exception e)
{
if (!methodInfo.Name.StartsWith("Get"))
Log(string.Format(
"In Dynamic Proxy- Exception {0} executing '{1}'", e),
methodCall.MethodName);
return new ReturnMessage(e, methodCall);
}
}
Figure 14 Filtering Methods for the Aspect
Figure 13 Output of the Program Using Two Proxies
pub lic class RepositoryFactory
{
public static IRepository<T> Create<T>()
{
var repository = new Repository<T>();
var decoratedRepository =
(IRepository<T>)new DynamicProxy<IRepository<T>>(
repository).GetTransparentProxy();
// Create a dynamic proxy for the class already decorated
decoratedRepository =
(IRepository<T>)new AuthenticationProxy<IRepository<T>>(
decoratedRepository).GetTransparentProxy();
return decoratedRepository;
}
}
Figure 11 The Repository Factory Decorated by Two Proxies