Sometime ago, I wrote this article for the MSDN Magazine, about Aspect Oriented Programming and how it could solve cross-cutting concerns in your application, like:
- Authentication
- Logging
- Data audit
- Data validation
- Data caching
- Performance measuring
The article shows how to use the Decorator pattern and the RealProxy class to create a Dynamic Proxy to solve these issues in a simple manner. If you want to have a full introduction on the subject, I suggest that you take a look at the article. The time has passed, things changed a lot and we are now close to the introduction of .NET 7. The RealProxy class doesn't exist anymore, as it's based in Remoting, which was not ported to .NET Core. Fortunately, we still have the System.Reflection.DispatchProxy class that can solve the problem.
With this class, we can still write proxies that decorate our classes and allow us to implement AOP in our programs. In this article, we will use the DispatchProxy class to create a dynamic proxy that allows us to implement a filter for the methods to be executed and execute other functions before and after the method execution.
In the command prompt, create a new console app with:
In Program.cs, we will define a Customer record (put it at the end of the code):
Then, add a new Repository.cs file and add an IRepository
The next step is to create the generic class Repository
As you can see, our repository class is a simple class that will store the entities in a list, delete and retrieve them.
With this class created, we can add the code to use it in Program.cs:
If you run this program, you will see something like this:
Now, let's say we want to implement logging to this class, and have a log entry for every time it enters a method and another entry when it exits. We could do that manually, but it would be cumbersome to add logging before and after every method.
Using the DispatchProxy class, we can implement a proxy that will add logging to any class that implements the IRepository
The RepositoryLogger class inherits from DispatchProxy and has a Create method that will create an instance of a class that implements the interface that's decorated. When we call the methods of this class, they are intercepted by the overriden Invoke method and we can add the logging before and after executing the method.
To use this new class, we can use something like:
Now, running the code, we get:
We have logging entering and exiting the class without having to change it. Remove logging is as simple as changing one line of code.
With this knowledge, we can extend our proxy class to do any action we want. To add actions before, after and on error is just a matter of passing them in the creation of the proxy. We can create a DynamicProxy class with this code:
In the Create method, we pass the actions we want to execute before after and on error after each method. We can also pass a predicate to filter the methods we don't want to execute. To use this new class, we can do something like this:
Executing this code will show something like:
Note that, with this code, the method GetAll isn't executed, as it was filtered by the predicate.
As you can see, this is a very powerful class, as it can implement many different aspects for any interface (the DispatchProxy class only works with interfaces). For example, if I want to create my own mocking framework, where I don't execute any method of a class, I can change the code of the Invoke method to
And create the proxy with something like this:
In this case, the real functions won't be called, just the methods before and after the call:
As you can see, the DispatchProxy class allows the creation of powerful classes that add aspects to your existing classes, without having to change them. With the DynamicProxy class you just have to add the actions to execute and the filter for the functions to be executed.
All the source code for this article is at https://github.com/bsonnino/DynamicProxy