ENTERPRISE

Microsoft .NET : Design Principles and Patterns - From Objects to Aspects (part 1) - Aspect-Oriented Programming

5/9/2013 9:30:09 PM
No doubt that OOP is currently a mainstream programming paradigm. When you design a system, you decompose it into components and map the components to classes. Classes hold data and deliver a behavior. 

Even with all of its undisputed positive qualities, though, OOP is not the perfect programming paradigm.

The OO paradigm excels when it comes to breaking a system down into components and describing processes through components. The OO paradigm also excels when you deal with the concerns of a component. However, the OO paradigm is not as effective when it comes to dealing with cross-cutting concerns.

A cross-cutting concern is a concern that affects multiple components in a system, such as logging, security, and exception handling. Not being a specific responsibility of a given component or family of components, a cross-cutting concern looks like an aspect of the system that must be dealt with at a different logical level, a level beyond application classes. Enter a new programming paradigm: aspect-oriented programming (AOP).

1. Aspect-Oriented Programming

The inherent limitations of the OO paradigm were identified quite a few years ago, not many years after the introduction of OOP. However, today AOP still is not widely implemented even though everybody agrees on the benefits it produces. The main reason for such a limited adoption is essentially the lack of proper tools. We are pretty sure the day that AOP is (even only partially) supported by the .NET platform will represent a watershed in the history of AOP.

The concept of AOP was developed at Xerox PARC laboratories in the 1990s. The team also developed the first (and still most popular) AOP language: AspectJ. Let’s discover more about AOP by exploring its key concepts.

Note

We owe to the Xerox PARC laboratories many software-related facilities we use every day. In addition to AOP (which we don’t exactly use every day), Xerox PARC is "responsible" for laser printers, Ethernet, and mouse-driven graphical user interfaces. They always churned out great ideas, but failed sometimes to push their widespread adoption—look at AOP. The lesson that everybody should learn from this is that technical excellence is not necessarily the key to success, not even in software. Some good commercial and marketing skills are always (strictly) required.

Cross-Cutting Concerns

AOP is about separating the implementation of cross-cutting concerns from the implementation of core concerns. For example, AOP is about separating a logger class from a task class so that multiple task classes can use the same logger and in different ways.

We have seen that dependency injection techniques allow you to inject—and quite easily, indeed—external dependencies in a class. A cross-cutting concern (for example, logging) can certainly be seen as an external dependency. So where’s the problem?

Dependency injection requires up-front design or refactoring, which is not always entirely possible in a large project or during the update of a legacy system.

In AOP, you wrap up a cross-cutting concern in a new component called an aspect. An aspect is a reusable component that encapsulates the behavior that multiple classes in your project require.

Processing Aspects

In a classic OOP scenario, your project is made of a number of source files, each implementing one or more classes, including those representing a cross-cutting concern such as logging. As shown in Figure 1, these classes are then processed by a compiler to produce executable code.

The classic OOP model of processing source code

Figure 1. The classic OOP model of processing source code

In an AOP scenario, on the other hand, aspects are not directly processed by the compiler. Aspects are in some way merged into the regular source code up to the point of producing code that can be processed by the compiler. If you are inclined to employ AspectJ, you use the Java programming language to write your classes and the AspectJ language to write aspects. AspectJ supports a custom syntax through which you indicate the expected behavior for the aspect. For example, a logging aspect might specify that it will log before and after a certain method is invoked and will validate input data, throwing an exception in case of invalid data.

In other words, an aspect describes a piece of standard and reusable code that you might want to inject in existing classes without touching the source code of these classes. (See Figure 2.)

The AOP model of processing source code

Figure 2. The AOP model of processing source code

In the AspectJ jargon, the weaver is a sort of preprocessor that takes aspects and weaves their content with classes. It produces output that the compiler can render to an executable.

In other AOP-like frameworks, you might not find an explicit weaver tool. However, in any case, the content of an aspect is always processed by the framework and results in some form of code injection. This is radically different from dependency injection. We mean that the code declared in an aspect will be invoked at some specific points in the body of classes that require that aspect.

Before we discuss an example in .NET, we need to introduce a few specific terms and clarify their intended meaning. These concepts and terms come from the original definition of AOP. We suggest that you do not try to map them literally to a specific AOP framework. We suggest, instead, that you try to understand the concepts—the pillars of AOP—and then use this knowledge to better and more quickly understand the details of a particular framework.

Inside AOP Aspects

As mentioned, an aspect is the implementation of a cross-cutting concern. In the definition of an aspect, you need to specify advice to apply at specific join points.

A join point represents a point in the class that requires the aspect. It can be the invocation of a method, the body of a method or the getter/setter of a property, or an exception handler. In general, a join point indicates the point where you want to inject the aspect’s code.

A pointcut represents a collection of join points. In AspectJ, pointcuts are defined by criteria using method names and wildcards. A sample pointcut might indicate that you group all calls to methods whose name begins with Get.

An advice refers to the code to inject in the target class. The code can be injected before, after, and around the join point. An advice is associated with a pointcut.

Here’s a quick example of an aspect defined using AspectJ:

public aspect MyAspect
{
  // Define a pointcut matched by all methods in the application whose name begins with
  // Get and accepting no arguments. (There are many other ways to define criteria.)
  public pointcut allGetMethods ():
         call (* Get*() );

  // Define an advice to run before any join points that matches the specified pointcut.
  before(): allGetMethods()
  {
    // Do your cross-cutting concern stuff here
    // for example, log about the method being executed
    .
    .
    .
  }
}

The weaver processes the aspect along with the source code (regular class-based source code) and generates raw material for the compiler. The code actually compiled ensures that an advice is invoked automatically by the AOP runtime whenever the execution flow reaches a join point in the matching pointcut.

AOP in .NET

When we turn to AOP, we essentially want our existing code to do extra things. And we want to achieve that without modifying the source code. We need to specify such extra things (advice) and where we want to execute them (join points). Let’s briefly go through these points from the perspective of the .NET Framework.

How can you express the semantic of aspects?

The ideal option is to create a custom language a là AspectJ. In this way, you can create an ad hoc aspect tailor-made to express advice at its configured pointcuts. If you have a custom language, though, you also need a tool to parse it—like a weaver.

A very cost-effective alternative is using an external file (for example, an XML file) where you write all the things you want to do and how to do it. An XML file is not ideal for defining source code; in such a file, you likely store mapping between types so that when a given type is assigned an aspect, another type is loaded that contains advice and instructions about how to join it to the execution flow. This is the approach taken by Microsoft’s Policy Injection Application Block (PIAB) that we’ll look at in a moment.

How can you inject an aspect’s advice into executable code?

There are two ways to weave a .NET executable. You can do that at compile time or at run time. Compile-time weaving is preferable, but in our opinion, it requires a strong commitment from a vendor. It can be accomplished by writing a weaver tool that reads the content of the aspect, parses the source code of the language (C#, Visual Basic .NET, and all of the other languages based on the .NET common type system), and produces modified source code, but source code that can still be compiled. If you want to be language independent, write a weaver tool that works on MSIL and apply that past the compilation step. Alternatively, you can write a brand new compiler that understands an extended syntax with ad hoc AOP keywords.

If you want to weave a .NET executable at run time, you have to review all known techniques to inject code dynamically. One is emitting JIT classes through Reflection.Emit; another one is based on the CLR’s Profiling API. The simplest of all is perhaps managing to have a proxy sitting in between the class’s aspects and its caller. In this case, the caller transparently invokes a proxy for the class’s aspects. The proxy, in turn, interweaves advice with regular code. This is the same mechanism used in .NET Remoting and Windows Communication Foundation (WCF) services.

Using a transparent proxy has the drawback of requiring that to apply AOP to the class, the class must derive from ContextBoundObject or MarshalByRefObject. This solution is employed by PIAB.

Other  
  •  Programming .NET Components : Serialization Events (part 3) - Type-Version Tolerance
  •  Programming .NET Components : Serialization Events (part 2) - Serialization Events and Class Hierarchies, Serialization and Versioning
  •  Programming .NET Components : Serialization Events (part 1) - Applying the Event Attributes
  •  All About Trackpads & Touchscreens
  •  Use Unified Communications To Optimize Business Procedures
  •  How To Buy A Tablet
  •  Best Brands In Electronic World (Part 2)
  •  Best Brands In Electronic World (Part 1)
  •  Top 10 Electronics Devices – May 2013
  •   Protect Your Business
  •  Downloading and Installing Nginx HTTP Server : Adding Nginx as a system service
  •  Downloading and Installing Nginx HTTP Server : Controlling the Nginx service
  •  Downloading and Installing Nginx HTTP Server : Configure options
  •  Windows System Programming : Exception Handling - Using Termination Handlers to Improve Program Quality, Using a Filter Function
  •  Windows System Programming : Exception Handling - Termination Handlers
  •  Performing mySAP.com Component Installations : Installation Details for mySAP Components
  •  Performing mySAP.com Component Installations : Installing Your mySAP-Enabling Foundation—NetWeaver
  •  Windows System Programming : Exception Handling - Treating Errors as Exceptions
  •  Windows System Programming : Exception Handling - Floating-Point Exceptions, Errors and Exceptions
  •  New Gadgets For April 2013 (Part 5)
  •  
    Most View
    Analysis iPhone Growth Strategy
    Samsung GALAXY Camera - The World's First Smart Camera
    Mobile Phones Buying Guide – April 2013 (Part 3) : HTC One X+, HTC Windows 8X, Huawei Ascend Pi
    Windows 7 : Protecting Your Network from Hackers and Snoops - Specific Configuration Steps for Windows 7
    Microsoft ASP.NET 3.5 : Caching Application Data (part 4) - Designing a Custom Dependency, A Cache Dependency for XML Data
    Best Photo Printers Revealed – Jan 2013 (Part 6)
    ScreenFlow 4 - Capture The Flag
    Planning a Windows 7 Client Update Strategy : Deploying Updates to Clients
    ASP.NET 4 in VB 2010 : The XML Classes (part 1) - The XML TextWriter
    SONY NEX-6 Camera - Good Value For Money (Part 1)
    Top 10
    CodeSport - Given The Importance Of Data Storage In A ‘Big Data’ World
    How To Clean A Virus-Infected PC
    How To Plan Home Improvements In 3D (Part 2)
    How To Plan Home Improvements In 3D (Part 1)
    How To Spellcheck In Any Application
    Apple’s Next Big Thing - Wearable Computing (Part 4)
    Apple’s Next Big Thing - Wearable Computing (Part 3)
    Apple’s Next Big Thing - Wearable Computing (Part 2)
    Apple’s Next Big Thing - Wearable Computing (Part 1)
    Droid Razr HD - 4G LTE Android Smartphone