ENTERPRISE

Microsoft .NET : Design Principles and Patterns - From Objects to Aspects (part 2) - AOP in Action

5/9/2013 9:31:12 PM

2. AOP in Action

To finish off our AOP overview, let’s proceed with a full example that demonstrates how to achieve AOP benefits in .NET applications. We’ll use Microsoft’s Policy Injection Application Block in Enterprise Library 3.0 and higher to add aspects to our demo. For more information on PIAB, see http://msdn.microsoft.com/en-us/library/cc511729.aspx.

Enabling Policies

The following code demonstrates a simple console application that uses the Unity IoC container to obtain a reference to a class that exposes a given interface—ICustomerServices:

public interface ICustomerServices
{
    void Delete(string customerID);
}

static void Main(string[] args)
{
    // Set up the IoC container
    UnityConfigurationSection section;
    section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
    IUnityContainer container = new UnityContainer();
    section.Containers.Default.Configure(container);
    // Resolve a reference to ICustomerServices. The actual class returned depends
    // on the content of the configuration section.
    ICustomerServices obj = container.Resolve<ICustomerServices>();

    // Enable policies on the object (for example, enable aspects)
    ICustomerServices svc = PolicyInjection.Wrap<ICustomerServices>(obj);

     // Invoke the object
     svc.Delete("ALFKI");

    // Wait until the user presses any key
    Console.ReadLine();
}

After you have resolved the dependency on the ICustomerServices interface, you pass the object to the PIAB layer so that it can wrap the object in a policy-enabled proxy. What PIAB refers to here as a policy is really like what many others call, instead, an aspect.

In the end, the Wrap static method wraps a given object in a proxy that is driven by the content of a new section in the configuration file. The section policyInjection defines the semantics of the aspect. Let’s have a look at the configuration file.

Defining Policies

PIAB is driven by the content of an ad hoc configuration section. There you find listed the policies that drive the behavior of generated proxies and that ultimately define aspects to be applied to the object within the proxy.

<policyInjection>
  <policies>
    <add name="Policy">
      <matchingRules>
        <add type="EnterpriseLibrary.PolicyInjection.MatchingRules.TypeMatchingRule ..."
             name="Type Matching Rule">
          <matches>
             <add match="ArchNet.Services.ICustomerServices" ignoreCase="false" />
          </matches>
        </add>
      </matchingRules>
      <handlers>
        <add order="0"
             type="ManagedDesign.Tools.DbLogger, mdTools"
             name="Logging Aspect" />
      </handlers>
    </add>
  </policies>
</policyInjection>

The matchingRules section expresses type-based criteria for a pointcut. It states that whenever the proxy wraps an object of type ICustomerServices it has to load and execute all listed handlers. The attribute order indicates the order in which the particular handler has to be invoked.

From this XML snippet, the result of this is that ICustomerServices is now a log-enabled type.

Defining Handlers

All that remains to be done—and it is the key step, indeed—is to take a look at the code for a sample handler. In this case, it is the DbLogger class:

public interface ILogger
{
    void LogMessage(string message);
    void LogMessage(string category, string message);
}

public class DbLogger : ILogger, ICallHandler
{
    // ILogger implementation
    public void LogMessage(string message)
    {
        Console.WriteLine(message);
    }
    public void LogMessage(string category, string message)
    {
        Console.WriteLine(string.Format("{0} - {1}", category, message));
    }

    // ICallHandler implementation
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        // Advice that runs BEFORE
        this.LogMessage("Begin ...");

        // Original method invoked on ICustomerServices
        IMethodReturn msg = getNext()(input, getNext);

        // Advice that runs AFTER
        this.LogMessage("End ...");

        return msg;
     }
     public int Order{ get; set; }
}

The class DbLogger implements two interfaces. One is its business-specific interface ILogger; the other (ICallHandler) is a PIAB-specific interface through which advice code is injected into the class’s aspect list. The implementation of ICallHandler is fairly standard. In the Invoke method, you basically redefine the flow you want for any aspect-ed methods.

In summary, whenever a method is invoked on a type that implements ICustomerServices, the execution is delegated to a PIAB proxy. The PIAB proxy recognizes a few handlers and invokes them in a pipeline. Each handler does the things it needs to do before the method executes. When done, it yields to the next handler delegate in the pipeline. The last handler in the chain yields to the object that executes its method. After that, the pipeline is retraced and each registered handler has its own chance to execute its postexecution code. Figure 3 shows the overall pipeline supported by PIAB.

The PIAB handler pipeline

Figure 3. The PIAB handler pipeline

Practical Advice for the Software Practitioner

To design good software, general principles are enough. You don’t strictly need patterns; but patterns, if recognized in a problem, are an effective and proven shortcut to get to the solution. Today, reinventing the wheel is a great sin, for yourself and your team.

Patterns are not essential to the solution of a problem. Using patterns won’t make your code necessarily better or faster. You can’t go to a customer and say "Hey, my product uses the composite pattern, a domain model, inversion of control, and strategy à gogo. So it’s really great." Patterns, if correctly applied, ensure that a problem will be solved. Take an easy approach to patterns, and don’t try to match a given pattern to a problem regardless of the costs of doing so.

Having mixed basic and OOD principles for years, we think we have now arranged our own few pearls of software design wisdom. These guide us every day, and we communicate them to all people we work with:

  • Group logically related responsibilities and factor them out to classes. In the factoring process, pay attention to forming extremely specialized classes.

  • Create concise and flexible abstractions of functionalities in classes. In this context, two other adjectives are commonly used in literature to describe abstractions: crisp and resilient.

  • When it comes to implementing classes, keep in mind separation of concerns—essentially, who does what—and make sure that each role is played by just one actor and each actor does the minimum possible; this is not done out of laziness, but just for simplicity and effectiveness.

Often referred to as KISS (short for Keep It Simple, Stupid), the idea of "simplicity above all" emerges in various forms from a number of heuristic principles that populate software design articles and conversations. The most popular principles are these:

  • Don’t Repeat Yourself (DRY). Refers to reducing duplication of any information needed by the application, and suggests you store the same information only in one place.

  • Once and Only Once (OAOO). Refers to reducing the number of times you write the code that accomplishes a given operation within an application.

  • You Aren’t Gonna Need It (YAGNI). Refers to adding any functionality to an application only when it proves absolutely necessary and unavoidable.

We often like to summarize the "simplicity above all" concept by paraphrasing people’s rights in court: everything you write can and will be used against you in a debugging session. And, worse yet, it will be used in every meeting with the customer.

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
    Keep Selective Colour In Mono Conversions (Part 1)
    Headset & Speaker Buyer’s Guide (Part 1)
    Acer Aspire V3-571 - Impressive Performance
    SQL Server 2005 : Working with SQL Server Management Objects in Visual Studio (part 2) - Retrieving Server Settings
    Laplink Disk Image Professional
    Tablets Buying Guide – April 2013 (Part 1)
    The Assemblage Of GeForce GTX 650 Ti Graphics Cards (Part 1)
    Wonderful Accessories For Your Life
    Be Quiet! Shadow Rock TopFlow SR1
    Matias Quiet Pro - Much More Versatile Than You Might Think
    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