Skip to content
Igor Tkachev edited this page May 20, 2016 · 1 revision

Home / Aspects

This aspect helps to collect statistical information for the members it is applied to.

CounterAspect.cs

using System;
using System.Reflection;

using NUnit.Framework;

using BLToolkit.Aspects;
using BLToolkit.Reflection;

namespace HowTo.Aspects
{
    [TestFixture]
    public class CounterAspectTest
    {
        public abstract class TestClass
        {
            // This is a method we collect statistic for.
            // Actually the entire class or even a base class 
            // can be decorated with the attribute.
            //
            [Counter]
            public virtual void TestMethod()
            {
            }
        }

        [Test]
        public void Test()
        {
            TestClass t = TypeAccessor<TestClass>.CreateInstance();

            for (int i = 0; i < 10; i++)
                t.TestMethod();

            MethodInfo     methodInfo = typeof(TestClass).GetMethod("TestMethod");
            MethodCallCounter counter = CounterAspect.GetCounter(methodInfo);

            Assert.AreEqual(10, counter.TotalCount);

            Console.WriteLine(@"
Method         : {0}.{1}
TotalCount     : {2}
ExceptionCount : {3}
CachedCount    : {4}
CurrentCalls   : {5}
TotalTime      : {6}
MinTime        : {7}
MaxTime        : {8}
AverageTime    : {9}
",
                counter.MethodInfo.DeclaringType.Name,
                counter.MethodInfo.Name,
                counter.TotalCount,              // total actual calls (no cached calls)
                counter.ExceptionCount,          // calls with exceptions
                counter.CachedCount,             // cached calls
                counter.CurrentCalls.Count,      // current calls (make sense for multithreading)
                counter.TotalTime,               // total work time
                counter.MinTime,                 // min call time
                counter.MaxTime,                 // max call time
                counter.AverageTime);            // average call time
        }
    }
}

BLToolkit type builder will generate the following for the class above:

[BLToolkitGenerated]
public sealed class TestClass : CounterAspectTest.TestClass
{
    private static CallMethodInfo _methodInfo;
    private static IInterceptor   _interceptor;

    public override void TestMethod()
    {
        if (_methodInfo == null)
        {
            _methodInfo = new CallMethodInfo((MethodInfo)MethodBase.GetCurrentMethod());
        }

        InterceptCallInfo info = new InterceptCallInfo();

        try
        {
            info.Object          = this;
            info.CallMethodInfo  = _methodInfo;
            info.InterceptResult = InterceptResult.Continue;
            info.InterceptType   = InterceptType.BeforeCall;

            if (_interceptor == null)
            {
                _interceptor = new CounterAspect();
                _interceptor.Init(_methodInfo, null);
            }

            // 'BeforeCall' creates or gets a counter for the method and 
            // registers the current call.
            // See the [link][file]Aspects/CounterAspect.cs[/file]CounterAspect.BeforeCall[/link] method for details.
            //
            _interceptor.Intercept(info);

            if (info.InterceptResult != InterceptResult.Return)
            {
                // Target method call.
                //
                base.TestMethod();
            }
        }
        catch (Exception exception)
        {
            info.Exception       = exception;
            info.InterceptResult = InterceptResult.Continue;
            info.InterceptType   = InterceptType.OnCatch;

            // 'OnCatch' is required to count calls with exceptions.
            //
            _interceptor.Intercept(info);

            if (info.InterceptResult != InterceptResult.Return)
            {
                throw;
            }
        }
        finally
        {
            info.InterceptResult = InterceptResult.Continue;
            info.InterceptType   = InterceptType.OnFinally;

            // 'OnFinally' step adds statistic to the method counter.
            // See the [link][file]Aspects/CounterAspect.cs[/file]CounterAspect.OnFinally[/link] method for details.
            //
            _interceptor.Intercept(info);
        }
    }
}

The following picture shows the information collected for data accessors of the BLToolkit.Demo.Asp.Net project.

Clone this wiki locally