Posts tagged with 'c'
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:
In a previous post, I showed off prototype's 'wrap' function, which gives JavaScript some AOP capabilities.
jQuery, a tool that I'm more familiar with, doesn't have an equivalent function that I know of. But there is a jQuery AOP plugin that provides a great AOP framework to your JavaScript.
While 'wrap' is akin to 'interception' style AOP, jQuery-aop includes some 'boundary' style aspects (as well as replacement/interception), including:
- before a method
- after a method
- when a method throws an exception
- when a method completes (exception or not)
- "around" a method
- replace a method (i.e. an "introduction")
There is some good API documentation available. Here's a little 101 example using "before" and "after":
Just paste that into an HTML file and run it in your browser, and you should get two alert messages. Since it's JavaScript, you can apply AOP to built-in functions like String.replace, or jQuery functions, just as easily as you can functions that you've written.
Here's the last post in my series of AOP terminology posts.
This week's term is "weaving".
Weaving is a general term to describe how an AOP tool combines an aspect with the rest of your code.
There are two main methods of weaving:
- Post-compiliation - modifying the code after the program already been compiled
- Runtime - Modifying/replacing the code while the program is running
Castle DynamicProxy uses runtime weaving. You can think of it as just like using the decorator pattern, except instead of coding each decorator by hand, Castle DynamicProxy will create those classes for you at runtime, by combining the IInterceptor implementation (that you've created) with the object that you want to intercept.
PostSharp is a post-compiler tool. It will take the aspect class that you've defined and actually modify your compiled program to weave it in to the methods/properties/etc you want it to intercept. I think a good way to visualize this is by using a decompiler to see what the code looks like before and after PostSharp has modified it.
Here's a very basic console app with a single aspect applied to a single method.
Here's what it looks like after compiling with PostSharp turned off and then decompiling (I used ILSpy as the decompiling tool this time):
Here's what it looks like after compiling with PostSharp turned on and then decompiling:
Don't panic, it's not as complicated as it looks: don't let the weird naming throw you off. Notice line 23: that's the only line that I wrote inside of the DoStuff method. The rest all comes from the aspect. The try/catch/finally structure was all put in to place by PostSharp. The first line of the method now calls the OnEntry method that I defined in the aspect. The OnSuccess method is the last thing called inside the Try. The OnException is called inside of the Catch. And OnExit is called inside of the Finally. (Note: they all get null arguments because I don't actually do anything of value inside the aspect, otherwise you'd also see some code to create the argument objects to pass in).
You can see that even though your source code is separated out into two classes, PostSharp does the work of weaving the cross-cutting concerns into the other method.
I've been trying on and off to figure out Mono.Cecil, and so far it's not very encouraging. It's a bit above my pay grade, it seems.
But all is not lost: I came across a tool while browsing NuGet called FireWeaver. It sits on top of Mono.Cecil, which means it does its work after compilation. It provides you with a way to replace a class with an entire other class. So it's not exactly intercepting or proxying classes, the way other AOP frameworks do: it flat out replaces it and is "essentially duct typing(sic) the entire object definition". I don't know if that's supposed to be "duct taping" or "duck typing", but I rather like the term "duct typing".
Here's a quick example of how it works, taken from the FireWeaver CodePlex site. First, I added FireWeaver with NuGet. Then I created a console app like this:
Compile and run as normal and here's the output:
Next, run the FireWeaver.Bootstrapper.exe tool against your assembly/assemblies. In my case, my Replace class is in the same assembly as the class it's replacing, so my arguments are identical, but you could certainly specify another assembly as the second argument:
And here's the output of the console app after I ran FireWeaver.
And here's what the assemblies look like (decompiled) before and after FireWeaver. Warning, your head may explode:
I'm just as confused about Cecil looking at these JustDecompile screenshots as I was before. But I assure you, it does work.
There's definitely some potential here, since this is a pretty easy tool to use, and integrating FireWeaver into your build script(s) shouldn't be too difficult if you don't want to hit the command line after every build. And it almost looks like pure duck typing brought to C#.
But this could also lead to some really wild code if you aren't careful with it. "Dogs and cats living together, mass hysteria" code.
I came across this question about interception vs injection on Programmer's Stack Exchange. Since I'm always blogging and talking about AOP, my thoughts immediately went to suggesting an AOP framework.
However, Mark Seeman wrote a very good answer about using the decorator pattern (or proxy pattern depending on how you look at it), and beyond being a good answer, it made me pause and think about the implications. If decorator/proxy combined with dependency injection does the job, why would I ever introduce an AOP tool?
Well, in many cases the answer is: I shouldn't! If I'm only applying cross-cutting concerns to a handful of classes, it's totally feasible for me to write out proxy/decorators and wire them up in my IoC container. Consider:
- 2 service interfaces: ICustomerRepository and IProductRepository
- 2 implementations: CustomerRepository and ProductRepository (which implement the interfaces respectively)
- 2 logging decorators: CustomerLoggingDecorator and ProductLoggingDecorator (which also implement the interfaces respectively)
- 2 caching decorators: CustomerCachingDecorator and ProductCachingDecorator (which also implement the interfaces respectively)
And there you go. No post-compile step, no runtime reflection generation, just you, 8 classes/interfaces and your IoC tool of choice. The logging and caching decorator classes could be very similar in their implementations, but it's not so bad, and I still get a nice separation of concerns, and all my implementations are single responsibility.
But now consider:
- 100 service interfaces: ICustomerRepository, IProductRepository, and 98 others...
- 100 service implementations: CustomerRepository, ProductRepository, and 98 others...
- 100 logging decorators: CustomerLoggingDecorator, ProductLoggingDecorator, and 98 others...
- 100 caching decorators: CustomerCachingDecorator, ProductCachingDecorator, and 98 others...
Whoa. Well, I still have a very nice separation of concerns, and I'm still following single responsibility. Wiring them up in a good IoC tool shouldn't be a problem, so long as I follow a good naming convention. So this isn't terrible.
But, now I have 400 classes/interfaces, most of which probably have very similar boilerplate code throughout. If I make a change to that boilerplate in one class, I have to change it in (possibly) 99 other classes. I still think this architecture is better than just tangling logging/caching code inside of the service implementations, it still leaves a lot to be desired.
Now consider an architecture using, say, Castle DynamicProxy:
- 100 service interfaces: ICustomerRepository, IProductRepository, and 98 others...
- 100 service implementations: CustomerRepository, ProductRepository, and 98 others...
- 1 logging interceptor class: LoggingInterceptor
- 1 caching interceptor class: CachingInterceptor
I think this is much better. No repetition with logging and caching decorators. I can still easily wire up the dependencies with a good IoC tool. If my logging or caching needs to change, I only need to change one place. If I actually need different logging or caching implementations, I can still do that. The only major difference is that now I have to use an AOP tool like DynamicProxy or PostSharp.
So, when should you use the decorator/proxy patterns and when should you use an AOP tool? With 2 service classes, you can definitely get by with your own decorators. With 100 service classes...maybe not so much. "Somewhere in between" is my weaselly answer.
- If you know your app will have a ton of service classes, you may as well start with an AOP tool.
- If you know your app will only have a small amount, you may as well stick to decorator/proxy.
- If you aren't sure, start with decorator/proxy and move to an AOP tool when you feel like there's too much boilerplate and repetition.
If you plan your architecture carefully, you can switch back and forth between tool and tool-less with a minimum of effort.