AOP and .NET
Eric Gunnerson asked for example code on what scenarios developers would use AOP for. Aspect Oriented Programming is another one of those software development areas that I'd love to know more about if there was spare time to look into it and experiment more. It looks promising, but it also looks like it is a potential nightmare with respect to understanding what a given piece of code does at runtime.
Taking a "requirements" driven approach, the following shows what I'd love to be able to do in the .NET development environment from a "plumbing" perspective. By plumbing, I mean boiler plate code that is repeated through out the source code. This boiler plate code is needed to get things done but sometimes hides the real application code. This applies equally to manually entered boiler plate code or the code generated equivalent. My perception is that AOP would be best suited to the implementation of this repetitive boiler plate code in an efficient manner. One of the .NET projects I'm currently working on implements the following areas of functionality using attribute based programming:
- Object Persistance - Properties
- Object Persistance - Query Methods
- Authorization defined at the class member level.
- Tracing (i.e. programmer level logging)
- Audit functionality defined at the class member level (i.e. application level logging of who made what object changes when)
All of these functionality areas could benefit from AOP style functionality which leverages both the attribute information and the specification of boiler plate code in one location in a source code project. Check out the following contrived example. Forget about the "made up" syntax used in this example code, the important part is the functionality need that is inherent in the example:
[ Persistable ]
public class Person
{
private string address;
[ Persistable ]
[ DenyRead(
typeof(Guest) ) ][ AllowWrite(
typeof(Administrator ), typeof(Manager) ) ][ LogWrite ]
public string Address
{
get { return aspect( ref address ); }
set { address = aspect( value, address ); }
}
[ Query(
typeof(BlogPost),"select ref(b) from BlogPost b where " +
"b.Poster.OID = @this and " +
"b.DateCreated >= @start and b.DateCreated <= @end" ) ]
[ TraceEntry ]
[ DenyExecute(
typeof(Guest) ) ][ LogExecution ]
public List<BlogPost> GetPosts( DateTime start,
DateTime end )
{
return aspect;
}
}
The [ Persistable ] attribute marked on the class would result in the class automatically including members to support the persistance of the object in something like ObjectSpaces. Marking a property as [ Persistable ] would automatically insert code which surrounds the get/set methods so that the object persistance mechanism is invoked transparently. The series of Allow/Deny attributes in the example code would result in the insertion of code that checks the user roles defined in the attribute parameters. If that user role isn't allowed to perform the action (get the property value, set the property value, execute the method) then an exception is thrown. Applications could check the type metadata to identify whether a user interface should allow the actions in the first place. The exceptions would only be thrown if the UI ignores this metadata.
The Query attribute is a means of defining a query to issue to persistence mechanism to get back a result object or list. The TraceEntry attribute functionality is the venerable programmer logging "aspect". The LogWrite and LogExecution attributes are oriented towards Auditing needs i.e. your application needs to log who retrieved a list of blog posts for that person and when they did it.