Let's build an error handling aspect: part 1
I've written a lot of AOP demos, given a lot of presentations on it (AOP For You and Me and The Class That Knew Too Much), and I even wrote a book about AOP in .NET. These aspects are all great places to start, but I thought I would take it a little deeper in a blog post series, detailing a real aspect I'm using in a real project, how I built it, and the reasoning behind the decisions I make. Because this is a much more practical example, this aspect is not generally applicable. You can't just drop it in to your project without tailoring it a bit. (If you are interested in those types of aspects, PostSharp has custom design patterns, ready for you to use today).
I'm only going to show you the basics of the aspect right now, and I'll build it up and add to it as this blog post series goes along. Note that this is an active project, and therefore it's still a work in progress. Part of the reason I'm doing this series is to help me get some real feedback!
My goal with this aspect is add error handling to my service layer. This service layer sits between my UI layer (an ASP.NET MVC application) and my data layer (which uses Dapper on a SQL Server database). When this aspect is done, it should:
- Catch exceptions
- Log (most) exceptions
- Ensure that a useful/helpful/friendly error message is given to the UI, instead of bubbling up the exception
- Make sure the service method returns something useful, if it's meant to return something
As an aspect, then, I can apply this to every public service method so that I don't have to worry about writing it over and over, and I don't have to worry about forgetting to add it to new service methods.
Let's start easy with a basic shell of an aspect:
I'm using MethodInterceptionAspect. I guess I could use OnMethodBoundaryAspect instead (or even OnExceptionAspect), since most of the code I'm going to write is going to end up being in that "catch" block. But let's just stick with this for now, and consider changing later (because of how PostSharp's API is structured, I know that this won't be very difficult).
Notice that there are two attributes on this aspect.
- [Serializable] - this is required by PostSharp, since PostSharp instantiates and serializes aspects at compile time.
- [MulticastAttributeUsage] - this is me telling PostSharp that I want to be able to multicast this aspect to public methods (see Aspects.cs below)
As it stands right now, this is not a good aspect, since it will just be swallowing all the exceptions. But it's as good as place to start as any, especially if you aren't familiar with AOP/PostSharp.
I'll also create another file in my project called Aspects.cs, which will contain assemly attributes so that I can apply this aspect to every method in the namespace where I put all my services.
I put an AspectPriority of "10" on it because I actually have another aspect in my project that I use to manage SQL transactions that has a priority of "20". I want the exception handling aspect to be the highest priority (lowest number).
Make sure you understand what's going on here before continuing. If not, you may want to review those presentations I linked to, check out the PostSharp documentation, or maybe check out my PostSharp Live webinar series.