AOP – Tracing methods in C# with PostSharp

Suppose you are tasked with adding logging to trace when a method starts and when it ends. Now suppose that you are tasked to do this for every method in a project, lets say you have to do this for 1,000 methods scattered throughout all your objects. Every method included would have two lines of logging code, one at the start, one at the end. That means you have to add two lines of code per method or 2,000 lines of code.  Sure, you could extract the logging methods into a static or singleton making it “easier”, but in the end, you still end up with 2,000 lines of code, two per method.

Is adding 2,000 lines of code the right solution? No it is not. These lines of code can be distracting and can make a method less readable. A single line method becomes three lines. Your class files get bigger, especially if they are method heavy. Also, these lines of code break the SOLID principles in that 1) you are repeating yourself, and 2) your method no longer has a single responsibility as it is doing what it was design for and it is doing tracing, etc. It doesn’t have to be this way.

AOP can allow you to do the same task but have the code in a single place. Including spaces and brackets, the C# MethodTracingAspect file is only 36 lines of code and to implement this into all methods in a namespace an AspectInfo.cs file is used with only three lines of code.

Which would you rather deal with: 39 lines of code in two class files, or 2,000 lines of code spread throughout ever class file?

This document assumes you have the done the following already:

  1. Installed Visual Studio
  2. Installed PostSharp
  3. Licensed PostSharp

Note: While PostSharp has a free version, my examples will likely require the licensed version.

Step 1 – Create a new C# project for Aspects

  1. In Visual Studio, choose File | New | Project.
  2. Choose a Visual C# Console Application.
  3. Give the project a Name.
    Note: I named my project AspectExamples
  4. Click Ok.

Your project is now created.

Step 2 – Add a reference to PostSharp

  1. In Solution Explorer, right-click on your new project and choose Add Reference.
  2. In the Add Reference window, click to select the .NET tab.
  3. Locate PostSharp and click to highlight it.
  4. Click Ok.

You have now added PostSharp as a reference to your project.

Step 3 – Create an Aspect for method tracing

  1. Right-click on your project and choose Add | Class.
  2. Give the class a Name.
    Note: I named my version of this class MethodTraceAspect.
  3. Add a using reference to the PostSharp.Aspects namespace.
  4. Make the object inherit from OnMethodBoundaryAspect.
  5. Override the OnEntry method.
  6. Override the OnExit method.
  7. Add code to each method for logging to the Output window using Debug.WriteLine().
    Note: Obviously, you can use any logging library you software may use.
  8. Add code to make sure that methods inside methods are properly tabbed.

Here is my final class file.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using PostSharp.Aspects;

namespace AspectsExamples
{
    [Serializable]
    public class MethodTraceAspect : OnMethodBoundaryAspect
    {
        private static int _TabCount = 0;
        private static Stack<long> _StartTimeStack = new Stack<long>();

        public override void OnEntry(MethodExecutionArgs args)
        {
            Debug.WriteLine(GetTabs() + "Method started: " + args.Method.Name);
            _TabCount++;
        }

        public override void OnExit(MethodExecutionArgs args)
        {
            _TabCount--;
            Debug.WriteLine(GetTabs() + "Method completed:" + args.Method.Name);
        }

        private static String GetTabs()
        {
            string tabs = string.Empty;
            for (int i = 0; i < _TabCount; i++)
            {
                tabs += "\t";
            }
            return tabs;
        }
    }
}

You now have a modular Aspect that you can use to add method start, method end logging to any method in any C# project.

Step 4 – Implement the Aspect for method tracing

Implementing the Aspect for method tracing is accomplished by using an Attribute. The attribute can be added to a single method, a class, or a namespace.

We will use the following Program.cs file will demonstrate this.

using System;

namespace AspectExamples
{
    class Program
    {
        static void Main(string[] args)
        {
            HelloWordMethod();
        }

        private static void HelloWordMethod()
        {
            Console.WriteLine("Hello, World!");
        }
    }
}

Option 1 – Adding the Aspect to methods

When adding this to method, you have to add it for each method.

  1. Add the MethodTraceAspect to the Main method.
  2. Add the MethodTraceAspect to the HelloWordMethod.
using System;

namespace AspectExamples
{
    class Program
    {
        [MethodTraceAspect]
        static void Main(string[] args)
        {
            HelloWordMethod();
        }

        [MethodTraceAspect]
        private static void HelloWordMethod()
        {
            Console.WriteLine("Hello, World!");
        }
    }
}

Ok, lets test this.

  1. Click Debug | Start Debugging to run the application in debug mode.
  2. Look at the Output and you should see the following lines.
Method started: Main
	Method started: HelloWordMethod
	Method completed:HelloWordMethod
Method completed:Main

Option 2 – Adding the Aspect to classes

When adding this to a class, you don’t have to add it for each method in the class.

  1. Add the MethodTraceAspect to the Program class.
using System;

namespace AspectExamples
{
    [MethodTraceAspect]
    class Program
    {
        static void Main(string[] args)
        {
            HelloWordMethod();
        }

        private static void HelloWordMethod()
        {
            Console.WriteLine("Hello, World!");
        }
    }
}

Ok, lets test this.

  1. Click Debug | Start Debugging to run the application in debug mode.
  2. Look at the Output and you should see the following lines.
Method started: Main
	Method started: HelloWordMethod
	Method completed:HelloWordMethod
Method completed:Main

Option 3 – Adding the Aspect to a namespace

When adding this to a namepsace, you don’t have to add it for each class or every method in each class. Instead it is automatically added to every method in every class in the namespace.

  1. Add the MethodTraceAspect to the namespace.
    Note: Notice the syntax is slight different for adding to a namespace than for a class or method.
using System;

[assembly: MethodTraceAspect]
namespace AspectExamples
{
    class Program
    {
        static void Main(string[] args)
        {
            HelloWordMethod();
        }

        private static void HelloWordMethod()
        {
            Console.WriteLine("Hello, World!");
        }
    }
}

Ok, lets test this.

  1. Click Debug | Start Debugging to run the application in debug mode.
  2. Look at the Output and you should see the following lines.
Method started: Main
	Method started: HelloWordMethod
	Method completed:HelloWordMethod
Method completed:Main

Note: For real projects that aren’t just examples, it is a good idea to implement Aspects to a namespace in a separate file, such as an AspectInfo.cs file.

using Common.Aspects;
[assembly: MethodTraceAspect]
namespace AspectExamples {}

Congratulations, you have implemented an Aspect in C# using PostSharp.

Return to Aspected Oriented Programming – Examples

Leave a Reply

How to post code in comments?