October, 2009 Archives
Oct
AOP in .NET with Unity Interception Model
by Mikael Lundin in Programming
AOP is a buzzword or acronym from a couple of years back, that never really took wind in the world of .NET or statically typed languages. It is a programming model where you try to move out all infrastructure logic from the main flow of the program into aspects that should be deployed solution wide. This is very hard to accomplish in a statically typed language and that is the main reason for its failure, but the theory of AOP has lived on through academics and professional technologists.
When Microsoft released version 1.2 of its dependency injection framework Unity, they also supplied support for AOP and they called it Policy Injection, in Enterprise Library 4, or plainly “interception” as a standalone Unity extension.
Building dependency chains
Unity is great at building dependency chains, because it was designed to do just that. By registering the dependency chain into a container you can simply ask that container to build you a CustomerRepository without the fuzz of creating a CustomerDataAccess and knowing where to find your instance of IDataFactory. This is also a great base to build our AOP model on.
var repository = Container.Instance.Resolve<CustomerRepository>(); var customer = repository.GetCustomerById(1);
The problem
A lot of our code may get repetitive where we use extensive logging that we would like to extract away from our code, since it is only noise. Please reflect over this example.
public Customer GetById(int id)
{
System.Diagnostics.Debug.WriteLine("CustomerDataAccess.GetById(" + id + ")"); // Noise
Customer result = null;
using (var connection = dataFactory.OpenConnection())
{
var command = connection.CreateCommand();
command.CommandText = "SELECT * FROM Customer WHERE id=" + id; // Beware of SQL injection
var reader = command.ExecuteReader();
result = reader.GetCustomer();
}
System.Diagnostics.Debug.WriteLine("CustomerDataAccess.GetById(" + id + ") -> " + result);
return result;
}
Wouldn’t it be great if we could extract these log messages and place them outside the method?
Unity interception
With interception we can define what we would like to do before the call of a method, and after the call of a method. This way we can put the noise that is not business logic outside the method which will make the code much easier to read. We start by creating a call handler that will handle the call to the method we would like to intercept.
public class LogCallHandler : ICallHandler
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
string className = input.MethodBase.DeclaringType.Name;
string methodName = input.MethodBase.Name;
string arguments = GetArgumentList(input.Arguments);
/* CustomerDataAccess.GetById(123) */
string preMethodMessage = string.Format("{0}.{1}({2})", className, methodName, arguments);
System.Diagnostics.Debug.WriteLine(preMethodMessage);
/* Call the method that was intercepted */
IMethodReturn msg = getNext()(input, getNext);
string postMethodMessage = string.Format("{0}.{1}() -> {2}", className, methodName, msg.ReturnValue);
System.Diagnostics.Debug.WriteLine(postMethodMessage);
return msg;
}
public int Order { get; set; }
}
The call handler is a class that implements the ICallHandler from the Microsoft.Practices.Unity.InterceptionExtension assembly, where the Invoke method will be the method interrupting the call to our method. The method will not be run until we execute the following statement.
- getNext()(input, getNext);
The next thing you need is logic that will decide when a method should be interrupted. You can see this as a filter as every method that can be resolved through unity will be target for interception unless you filter it away. The implementation looks like this.
public class AnyMatchingRule : IMatchingRule
{
public bool Matches(MethodBase member)
{
return true;
}
}
I’ve written the easiest and dumbest matching rule ever. It will just match anything that comes in its way, and that will be enough for this simple example. If you need total control you might want a register of what method you should interrupt and match the MethodBase to that register. Just a thought.
Now we only have to connect the dots. It looks like this.
public class Container : UnityContainer
{
public void Configure()
{
/* Register types into the container */
RegisterType<IDataFactory, StubDataFactory>();
RegisterType<IDataAccess<Customer>, CustomerDataAccess>();
/* Register our matching rule and call handler */
RegisterType<IMatchingRule, AnyMatchingRule>("AnyMatchingRule");
RegisterType<ICallHandler, LogCallHandler>("LogCallHandler");
/* Create a new policy and reference the matching rule and call handler by name */
AddNewExtension<Interception>();
Configure<Interception>().AddPolicy("LogPolicy")
.AddMatchingRule("AnyMatchingRule")
.AddCallHandler("LogCallHandler");
/* Make IDataAccess interface elegible for interception */
Configure<Interception>().SetInterceptorFor(typeof(IDataAccess<>), new TransparentProxyInterceptor());
}
}
In the first two lines we register our dependencies as usual. Then we also register the matching rule and the call handier that we’ve just created. You could create your own instances of these, but why when you have a container that can handle them.
After that the interception configuration comes. It starts with adding the extension to the container. Then we register a new policy and add our matching rule and call handler to that policy. Last, we tell the container what type to intercept, and here we choose to intercept an open generic of the IDataAccess interface. That means that we will intercept any implementation of the IDataAccess, no matter if its generic class of Customer or something else.
When we run the following code
var container = new Container(); container.Configure(); var dataAccess = container.Resolve<IDataAccess<Customer>>(); dataAccess.GetById(1);
We get this output
IDataAccess`1<AopExample.Customer>.GetById(1)
IDataAccess`1<AopExample.Customer>.GetById() -> Customer { Id = 1, Name = John Doe }
Where the logging actually comes from the LogCallHandler and not from the data access code. Neat huh? You can download the full example from here.
Oct
Self documenting code is not code without comments
by Mikael Lundin in Programming
I was discussing this topic with a fellow developer today that was reading Clean Code, in which Uncle Bob reasons that you should write self documenting code.
I cannot tell you what Uncle Bob says in his book, since I haven’t read it, but from my colleague it sounded as self documenting code should not be commented. What I believe that Robert means, is that we should not document the obvious.
/* Add a with b */ c = a + b
If you write self documenting code you don’t have to document the obvious. But you still have to document things that are not obvious through reading the code. Let’s say, the method returns null.
/// <returns>Null when user is not found</returns>
public User GetUserById(int id)
{
}
You also need to comment your code to show your intent. Reflect on the following.
/* Extract method */
if (Page.IsPublished && !Page.IsDeleted && Page.IsVisibleInMenus)
{
}
I want you to see comments as scribblings in the margin of a book. You don’t scribble the same things that is already written but comments for yourself and others to give better understanding of the code.
Oct
Refactor to simplify
by Mikael Lundin in Technicalities
/// <summary>Don't change this unless you're a genius like me</summary> /// TODO: Refactor to simplify
One of the most qualified developers I’ve met told me during a code review that “you’ll not have to explain that piece of code, because I won’t understand it anyway”.
A big red warning sign flashes in my head!
When you write code you have more than one audience
- The client will never read the code that you write, but he will notice the quality that you deliver. Well written code with high quality will make clients happy, because they very seldom notice any bugs.This is where the focus of most developers lie.
- Your largest consumer base is hopefully your client and their customers. Next to that are readers of your code. Readability is also a very important aspect for your client. More readable code will be easier to bug fix and your client will waste less money on maintenance.Writing readable code is hard but it goes hand in hand with quality.
- Most developers forget that they’re also writing code for other developers to extend. Writing code for writers is even less common than writing readable code. This means that you create code that is very easy to change. As a developer you will constantly review how to change your code and extend it with more validation rules, service calls, entities or simply how to scale the whole application on several web servers.Writing code that is adaptable for change is both hard and dangerous.
When you write some code that is too hard for others to understand you have a problem on your hands. It might be the result of over design where you intend to make the system so dynamic that none except yourself will understand how to manage change. If you can’t suffer the loss of complexity you will have to create an additional layer of abstraction. That layer will be invisible to the customer, but very important for other developers for both readability and changeability. That will in time save the client money.
- Manage defects
- Manage change
- Manage complexity
If it was easy, you wouldn’t be doing it.