Posts tagged with 'IL'
Week #2 is coming to an end here at CrossCuttingConcerns, which means it's time for another link dump post.
- LIDNUG (Linked-in .NET user group) recently posted video of Gael Fraiteur at their user group meeting. This was recorded in November 2010, so it's a bit behind the times as far as PostSharp goes, but it's still an informative video.
- Here's a white paper comparing AOP to composition filters (CF). I've not heard of CF before this paper, but it seems that like AOP, CF aims to address the same limitations with cross-cutting concerns that AOP does. (PDF link)
- Taking the Single Responsibility Principle (SRP) seriously. A deep dive into SRP, and just what is a "responsibility" anyway?
- Another white paper, but this one is about an interesting use case of AOP. It's based on a project to "trace" an application: not in the traditional developer sense of tracing through the code, but rather tracing a user's actions as she uses the interface to a system. And then using that information for later analysis (perhaps a usability study?).
- A blog post from Kristijan Rebernišak about using AOP to check user permissions: he uses Google Guice with AOPAlliance.
- Chad England has started a blog post series on AOP with PostSharp.
Thanks for reading, and please leave a comment or use the contact link above if there's something you'd like to see covered here on CrossCuttingConcerns.com (or if you have something to say and want it published here).
Recently I was made aware of another AOP tool for .NET that uses a post-compile step to do the weaving (similar to PostSharp). SheepAspect appears to use the Mono.Cecil library, which is a powerful utility to work with CIL assemblies. I mentioned SheepAspect in an earlier post, and I thought it deserved a closer look.
SheepAspect is available via NuGet, so it's an easy install. Here's a 'Hello, World' aspect in a console app that I threw together:
It's a somewhat unfamiliar approach to me, being used to PostSharp.
- To define an aspect, create a class and put the [Aspect] attribute on it. So far so good.
- You don't use attributes to apply the aspect to your code. Notice that MyClass and DoStuff are not decorated with any attributes.
- Instead, you define a pointcut by creating an empty "marker" method (MyPointcut in the above example), and placing a selector attribute on that. The one I'm using is SelectMethods, but there are others available.
- The string in that SelectMethods attribute is called SheepAop Query Language (SAQL).
- The advice goes into the InterceptMethod method, which returns an object and gets an MethodJointPoint (yes MethodJointPoint, not MethodJoinPoint, that's not a typo). MethodJointPoint is very similar to DynamicProxy's IIntercept or PostSharp's MethodInterceptionArgs, in that it gives you a context to work with.
- I put an "Around" attribute on this method to specify that I want this advice to surround the pointcut, and I specified the pointcut with the string.
Compile and run, and here's the output:
After using SheepAspect in this admittedly trivial way, I do think it has some potential, but it also feels like a project that's in its very early stages and is a little rough around the edges still.
- SAQL is a very interesting way to select pointcuts, and based on the SAQL documentation that I've read, it can be very powerful. This is a double-edged sword though: this query language is specific to SheepAspect, so you'll have to spend some time learning it to get the most use out of it.
- SAQL queries are just strings, so refactoring/renaming could be problematic. Perhaps if you are coming from an AspectJ environment, this would not be as difficult, since that's what SheepAspect seems to modeled on. A Linq provider would be tremendous, but that might be very ambitious, if not impossible.
- The fact that SheepAspects are only connected to your regular code by SAQL is also an interesting approach: your pre-compile source code goes completely untouched, which is nice and clean, but it could also be hard to keep track of what aspects are being applied where.
- Finally, while there is some good documentation, it looks like some of it has yet to be written, which indicates to me that it's still very much a work in progress.
I can't say I'd recommend using SheepAspect over more mature and supported tools like PostSharp or Castle DynamicProxy, but it might be worth a look for specialized usage in low risk situations. In the future, who knows; it could develop into a very popular tool.
Building on the overview of ActionFilters in MVC, I'm going to go into a deeper dive on the various overrides that you can use inside of an ActionFilter, starting with OnActionExecuting.
OnActionExecuting is run before the Action is executed. You can put whatever code you want in here, including something as simple as just writing some raw HTML out before the Action is executed. But the real power comes from the filterContext parameter (of type ActionExecutingContext) that gets passed in to your OnActionExecuting method. This object gives you a whole bunch of information about the current context of the action that you are filtering. You can use this information to control logic or, conversely, you can manipulate the context according to your logic.
I wrote a "kitchen sink" filter combined with a Razor view to give you an idea of what kind of context you can view and/or manipulate.
All this does is expose the filterContext object to the view, where I can display some of the information available.
Here's a screenshot of the output. Note the URL (/Home/Index/parameter_value_here?anotherParam=99) as you look through the screenshot.
I've broken this output into 4 sections of different context information you can get. The first 4 are ASP.NET MVC specific: Controller, Action, Action Result, and Route. The last one, Http Context, is more general to ASP.NET.
Controller
You can get the controller name, the controller type, and even the controller instance, depending on your need. You can try to cast the controller to a specific controller if you want and access properties of that controller (I wouldn't recommend that generally, but you'll note that's how I did my kitchen sink action filter, by casting to the HomeController type).
Once you have a controller instance, you can access ViewBag, ViewData, TempData, all of which allows you to communicate to the action (and ultimately the view) if you choose to.
You can also access custom attributes here, which opens up some possibilities in declarative programming and use of metadata.
Action
You can again, get the name (of the action this time) if you want just that. You can also get some reflection information about the parameters. If you look at ActionParameters, you can get the parameter names along with the arguments. And once again, you can access custom attributes here, just as you can with controllers.
Action Result
You have the ability to get the ActionResult that the Action will return. At this point in the life cycle, that ActionResult is probably null, so I'm not exactly sure what you would want to do with it. But it's there. You could create a RedirectResult and immediately execute it; I suppose that might come in handy.
Route
I generally would not recommend messing around with routes in your action filters, as things could get really confusing in ASP.NET MVC, but you have access to RouteData, Values and DataTokens here too.
Http Context
Finally, Http Context, which contains just about everything you need to work with your standard Http objects like Response, Request, Session, etc. Do note that the objects you get are generally base classes (e.g. HttpResponseBase and HttpRequestBase), so you may not have access to some of the methods and properties that you are used to.
With the Http Context available, you can do some interesting things like checking to see if the session expired, and then either reloading the session from a db or cookie or something, or redirecting to a 'timeout' or other message page.
There's more?
This isn't even an exhaustive list of the stuff you can get to via the ActionExecutingContext being passed in. I've just tried to list some of the more useful properties and examples of data that could be in those properties and left out the esoteric stuff. But there's a lot of power here to do almost anything you want before an action starts executing.
You're going to see very similar properties in the other action filter override context objects, but there are some differences that I'll explore in later posts.
AOP may sound like this big high-falutin' term that's way too complicated, but guess what: you may already be using AOP and you don't even know it.
Do you using ASP.NET MVC? Ever used an ActionFilter? Congratulations, you have used aspect-oriented programming. If you are using MVC and haven't used an ActionFilter yet, read on, because you may want to start!
Writing an ActionFilter is very similar to writing a PostSharp aspect: you create a new class that inherits from a base class (ActionFilterAttribute), and then you override one or more methods depending on what you want the ActionFilter to do. You apply the aspect to a method or entire class with an attribute. Unlike PostSharp, this form of AOP does not involve a post-compile step. The filtering takes place at runtime, and is invoked by the MVC framework. This means that if you are writing a unit test against the controller action, that test will not trigger the ActionFilter.
I'm going to be blogging some more details about what you can do with each of these, but when you are creating a class that inherits from ActionFilterAttribute, there are 4 methods that you can override 1 or more of:
- OnActionExecuting - runs before the affected action
- OnActionExecuted - runs after the affected action
- OnResultExecuting - runs before the result of the action runs
- OnResultExecuted - runs after the result of the action runs
If you use the [Authorize] attribute in MVC, then you are using an ActionFilter that's been pre-written for you (technically AuthorizeAttribute inherits from FilterAttribute, but it's the same principle). Instead of checking the User.Identity inside every one of your Controller actions, you can just slap the [Authorize] attribute on it and it will keep that cross-cutting concern encapsulated away from the rest of your Controller logic.