AspectF fluent way to put Aspects into your code for separation of concern

Aspects are common features that you write every now and then in different parts of your project. it can be some specific way of handling exceptions in your code, or logging method calls, or timing execution of methods, or retrying some methods and so on. If you are not doing it using any Aspect Oriented Programming framework, then you are repeating a lot of similar code throughout the project, which is making your code hard to maintain. For ex, say you have a business layer where methods need to be logged, errors need to be handled in a certain way, execution needs to be timed, database operations need to be retried and so on. So, you write code like this:

public bool InsertCustomer(string firstName, string lastName, int age, 
    Dictionary<string, string> attributes)
{
    if (string.IsNullOrEmpty(firstName)) 
        throw new ApplicationException("first name cannot be empty");

    if (string.IsNullOrEmpty(lastName))
        throw new ApplicationException("last name cannot be empty");

    if (age < 0)
        throw new ApplicationException("Age must be non-zero");

    if (null == attributes)
        throw new ApplicationException("Attributes must not be null");

    // Log customer inserts and time the execution
    Logger.Writer.WriteLine("Inserting customer data...");
    DateTime start = DateTime.Now;

    try
    {
        CustomerData data = new CustomerData();
        bool result = data.Insert(firstName, lastName, age, attributes);
        if (result == true)
        {
            Logger.Writer.Write("Successfully inserted customer data in " 
                + (DateTime.Now-start).TotalSeconds + " seconds");
        }
        return result;
    }
    catch (Exception x)
    {
        // Try once more, may be it was a network blip or some temporary downtime
        try
        {
            CustomerData data = new CustomerData();
            if (result == true)
            {
                Logger.Writer.Write("Successfully inserted customer data in " 
                    + (DateTime.Now-start).TotalSeconds + " seconds");
            }
            return result;
        }
        catch 
        {
            // Failed on retry, safe to assume permanent failure.

            // Log the exceptions produced
            Exception current = x;
            int indent = 0;
            while (current != null)
            {
                string message = new string(Enumerable.Repeat('\t', indent).ToArray())
                    + current.Message;
                Debug.WriteLine(message);
                Logger.Writer.WriteLine(message);
                current = current.InnerException;
                indent++;
            }
            Debug.WriteLine(x.StackTrace);
            Logger.Writer.WriteLine(x.StackTrace);

            return false;
        }
    }

}

Here  you see the two lines of real code, which inserts the Customer calling a class, is hardly visible due to all the concerns (log, retry, exception handling, timing) you have to implement in business layer. There’s validation, error handling, caching, logging, timing, auditing, retring, dependency resolving and what not in business layers nowadays. The more a project matures, the more concerns get into your codebase. So, you keep copying and pasting boilerplate codes and write the tiny amount of real stuff somewhere inside that boilerplate. What’s worse, you have to do this for every business layer method. Say now you want to add a UpdateCustomer method in your business layer. you have to copy all the concerns again and put the two lines of real code somewhere inside that boilerplate.

Think of a scenario where you have to make a project wide change on how errors are handled. You have to go through all the hundreds of business layer functions you wrote and change it one by one. Say you need to change the way you time execution. You have to go through hundreds of functions again and do that.

Aspect Oriented Programming solves these challenges. When you are doing AOP, you do it the cool way:

[EnsureNonNullParameters]
[
Log]
[
TimeExecution]
[
RetryOnceOnFailure] public void InsertCustomerTheCoolway(string firstName, string lastName, int age, Dictionary<string, string> attributes) { CustomerData data = new CustomerData(); data.Insert(firstName, lastName, age, attributes); }

Here you have separated the common stuffs like logging, timing, retrying, validation, which are formally called ‘concern’, completely out of your real code. The method is nice and clean, to the point. All the concerns are taken out of the code of the function and added to the function using Attribute. Each Attribute here represents one Aspect. For example, you can add Logging aspect to any function just by adding the Log attribute. Whatever AOP framework you use, the framework ensures the Aspects are weaved into the code either at build time or at runtime.

There are AOP frameworks which allows you to weave the Aspects at compile time by using post build events and IL manipulations eg PostSharp, some does it at runtime using DynamicProxy and some requires your classes to inherit from ContextBoundObject in order to support Aspects using C# built-in features. All of these have some barrier to entry, you have to justify using some external library, do enough performance test to make sure the libraries scale and so on. What you need is a dead simple way to achieve “separation of concern”, may not be full blown Aspect Oriented Programming. Remember, the purpose here is separation of concern and keep code nice and clean.

So, let me show you a dead simple way of separation of concern, writing standard C# code, no Attribute or IL manipulation black magics, simple calls to classes and delegates, yet achieve nice separation of concern in a reusable and maintainable way. Best of all, it’s light, just one small class.

public void InsertCustomerTheEasyWay(string firstName, string lastName, int age,
    Dictionary<string, string> attributes)
{
    AspectF.Define
        .Log(Logger.Writer, "Inserting customer the easy way")
        .HowLong(Logger.Writer, "Starting customer insert", 
"Inserted customer in {1} seconds") .Retry() .Do(() => { CustomerData data = new CustomerData(); data.Insert(firstName, lastName, age, attributes); }); }

If you want to read details about how it works and it can save you hundreds of hours of repeatetive coding, read on:

AspectF fluent way to add Aspects for cleaner maintainable code

If you like it, please vote for me!

Burn! kick it Shout it
Published Sat, Sep 19 2009 10:59 by omar
Filed under: ,

Comments

# AspectF fluent way to add Aspects for clearner and more maintable code

Saturday, September 19, 2009 5:02 AM by DotNetKicks.com

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# AspectF fluent way to put Aspects for cleaner and more maintable code

Saturday, September 19, 2009 5:05 AM by DotNetShoutout

Thank you for submitting this cool story - Trackback from DotNetShoutout

# AspectF fluent way to put Aspects infor cleaner and maintainable code

Saturday, September 19, 2009 5:07 AM by DotNetBurner - ASP.net Ajax

DotNetBurner - burning hot .net content

# re: AspectF fluent way to put Aspects into your code for separation of concern

Monday, September 21, 2009 12:13 PM by pawel

so simple, so great solution

# re: AspectF fluent way to put Aspects into your code for separation of concern

Tuesday, September 22, 2009 3:12 AM by Co

The retry option does not work as it will execute even if the call to the work is done OK.

From your example:

AspectF.Define

      .Retry()

      .Do(() =>

{

 CustomerData data = new CustomerData();

 data.Insert(firstName, lastName, age, attributes);

}

);

# re: AspectF fluent way to put Aspects into your code for separation of concern

Tuesday, September 22, 2009 3:24 AM by omar

Good catch! I fixed it. A return was missing in Retry function.

# re: AspectF fluent way to put Aspects into your code for separation of concern

Tuesday, September 22, 2009 3:39 AM by Co

Glad to help.

I like this method to the PostSharp way. I do not like post processing of my code, obfuscation and copy protection is more than what I like but have to live with.

This will work well if you keep the "Aspects" simple like logging, retries ect. If you don't it will make the code more difficult to maintain.

Very well done!

# re: AspectF fluent way to put Aspects into your code for separation of concern

Tuesday, September 22, 2009 6:01 AM by omar

My future plans for aspects are:

Cache

 Auto cache method return value based on hash of input parameters or custom defined key.

Policy

Integrate with EntLib policy block to execute code when policy satisfies.

Rule

Simple rule engine to support running rules against input parameter and execute code when rules satisfy.

Any other recommendation?

# re: AspectF fluent way to put Aspects into your code for separation of concern

Tuesday, September 22, 2009 10:02 AM by Moim

Superb one!!

I am amazed by the first look on this idea..no doubt you've shown your talent once again!! Brilliant!

Right now in a hurry- leaving office..but I will think about this again with more concentration :) Just to consider possibilities if how it fits into my works :)

"My future plans for aspects are:

.....

Any other recommendation?"

I guess, you should try to fit the "Transaction management" into this framework. because IMHO, most of the people picks AOP stuffs to maintain transactions  rather than Logging, validations etc (at least this is true for JAVA world).

Once again...Best wishes for this Great Job!!!

# re: AspectF fluent way to put Aspects into your code for separation of concern

Thursday, September 24, 2009 4:56 AM by Brijesh

Great article.

I see that you have included it in dropthings.com project.

when you are planning to release it as a new version of dropthings ?

# re: AspectF fluent way to put Aspects into your code for separation of concern

Sunday, October 11, 2009 12:02 AM by Gloin

I bookmarked this link. Thank you for good job!,

# AspectF fluent way to put Aspects into your code for separation of concern

Sunday, October 11, 2009 8:05 PM by PimpThisBlog.com

Thank you for submitting this cool story - Trackback from PimpThisBlog.com

# re: AspectF fluent way to put Aspects into your code for separation of concern

Thursday, November 26, 2009 12:23 PM by Johannes

Brilliant.. simple, extendable with no performance penalties. Thank you plenty!!

Using it on a Repository<T>, UnitOfWork dance. Helped separating the UnitOfWork, caching, mapping and other concerns.

Here is an example of a typical UnitOfWork:

Aspect.Define

  .RemoveCache(EntityCacheKeys.ForCustomerPreferences(customerID))

  .UnitOfWork(repository=>

{

  Customer customer = repository.Find(customerID);

var pref = …..

repository.Add(pref));

}

# re: AspectF fluent way to put Aspects into your code for separation of concern

Friday, November 27, 2009 2:37 AM by Alex

Omar, that looks great.

According to my experience with extension methods and delegates/lambda expressions like you have in example (inside method .Do()),

Can we predict the stack trace of exception if occured?

I mean, will it be clear to understand in what place it occured?

Hope you got my thoughts.

Sincerely yours, Alex

# re: AspectF fluent way to put Aspects into your code for separation of concern

Friday, November 27, 2009 7:31 AM by omar

Hi Johannes, would you be interested to join the AspectF development and contribute your enhancement/fixes there? You just need to get a GoogleID and I will make you a "developer" in the project. Then you check directly checkin code in the repository.

I would love to have the enhancements you made.

Leave a Comment

(required) 
(required) 
(optional)
(required)