One of my core motivations for using AOP is that it can bring the single responsibility principle to places that would otherwise be difficult or impossible without AOP.
To review, here's the single responsibility principle in a nutshell:
A class should have one, and only one, reason to change.
Why is this a good principle? I think that the ObjectMentor white paper on SRP [PDF] sums it up very nicely, but basically if you have multiple concerns in a single class, those concerns become tangled together. This isn't a huge problem until you need to make a change (which never happens in software, right?). If I want to change responsibility A, I now have to involve the code for responsibilities A and B (and C and D, etc). All these responsibilities are coupled. If I make a change, I could break the class in multiple ways, affecting every one of the coupled concerns (unless I have a good suite of unit tests, which is unlikely if I have a very coupled set of concerns).
To avoid coupling, a good rule of thumb that I use is to describe what a class does in one sentence. If I have to use the word "and", then it's probably doing too much, and should be split into 2 or more classes.
Examples:
- PersonRepository: this class persists person objects to a database. Check! There's no "and", so this class is only doing one thing.
- BillPayService: this class submits transactions to the payment processor and stores payment history in an audit database. Bzzt! It's doing two things. Maybe I should consider a PaymentProcessorService and a PaymentHistoryRepository refactor.
- AccountController: this class routes the user to the appropriate account views (and logs any invalid request errors). I'll stop belaboring the point and leave this an an exercise to the reader.
In a previous terminology post on "advice", I pluralized advice to "advices" without even thinking about it.
Alexey Berezkin asks what the plural of "advice" actually should be, since "advices" isn't actually a valid English word. My answer is that "advices" is okay in the context of aspect-oriented programming, since it's basically jargon at that point.
Probably most correct would be "advice classes" or "advice instances", depending on the context. Advice classes are what I write using PostSharp, and advice instances are what get instantiated by the code that PostSharp's post compiler weaves into the rest of the code. "Advices" is sort of an overarching piece of jargon that covers both.
This is the last post of a series of posts about using ASP.NET's ActionFilter.
The last method that you can override in an ActionFilter is OnResultExecute, which runs after the result of a controller action has been executed.
An argument of type ResultExecutedContext gets passed in to OnResultExecute. It's not wildly different from ResultExecutingContext, except that instead of a "Cancel" member, you get a "Canceled" member, which just tells you after the fact if the action was cancelled or not. You can still access HttpContext, the Controller object, the Result, the RouteData, etc.
I can't really create another kitchen sink view like I could with the previous blog posts, because the ActionResult (usually a ViewResult) has already been executed. (I could still write to the Http Response, but that would be a little tedious).
Since OnResultExecuted can't output to the view, it's somewhat limited in its general usefulness. Logging, of course, can still be done here. Last minute changes to the HttpResponse might be a good use of this filter. You can still handle some exceptions, though using a HandleErrorAttribute filter might be a better idea for that.
I took last week off to let my link collection build up a little bit. Now back to your regularly scheduled lazy blog post with just links:
- Aspect-oriented programming with Action<> - Using proxy/decorator is one way of doing "poor man's AOP", but you can also use Action to just individually wrap (or decorate/proxy if you like) methods.
- .NET TV has a video of Mark Seeman's presentation about using Aspect-Oriented programming with Dependency Injection.
- Here's an intro on using Spring (Java) for AOP.
- AutoProxy (Java) for AOP with Spring. This might be worth more detailed follow-up, if I knew what the heck a "bean" was.
Have a good weekend!
Here's a quick example of how to write a caching aspect with Castle DynamicProxy.
First, let's write an implementation and a service worth caching:
Next, you need to decide where to cache the results. If you're using a web app, maybe try ASP.NET's Cache object. If you're writing an Azure app, try AppFabric caching. You can cache things in a database, a text file, whatever is appropriate for your application.
For this simple example, I'm going to cache everything in memory, in a static Dictionary object. Also, nothing that goes into my cache will ever expire or be invalidated. Once it's cached, it's cached forever. Also, it's not thread safe. Not a very useful cache in a real app, so let me just be clear: do not use this in a production application. It's only for demonstration: whatever you use for caching is up to you, I'm just demonstrating the aspect part.
I'm generating the cache key by appending the argument values to the method name. So if you call MyMethod("test") and MyMethod("test2"), that's two different keys that will cache two different results. This might work for you, or you might need a more complex GenerateCacheKey method (something that uniquely identifies objects, perhaps).
Next, I wire up my IoC container to return MyService when asked for an implementation of IMyService. But I also have to make sure that my IoC container (StructureMap in this case) applies the caching interceptor to it.
I put it all together in a simple console app:
And here's the result: