Skip to content

Event Action Aspect

Sagi edited this page Aug 10, 2015 · 3 revisions

Let's change a bit the contract that we've created in the Atom Composite example by adding a OnCodeCompleted event.

using NCop.Mixins.Framework;
using NCop.Composite.Framework;

[TransientComposite]
[Mixins(typeof(CSharpDeveloperMixin))]
public interface IDeveloper
{
    event Action OnCodeCompleted;
    void Code();
}

public class CSharpDeveloperMixin : IDeveloper
{
    public event Action OnCodeCompleted;

    public void Code() {
        var onCodeCompleted = OnCodeCompleted;

        Console.WriteLine("C# coding");

        if (onCodeCompleted != null) {
            onCodeCompleted();
        }
    }
}

We want to apply the aspect on the OnCodeCompleted event therefore we need to create a new aspect that is derived from EventActionInterceptionAspect.

When you derive from an event interception aspect you'll get the option to insert pieces of code in several points in the program (a.k.a join points):

  1. OnAddHandler - Called when a new delegate is added to this event.
  2. OnInvokeHandler - Called when the event to which the current aspect is applied is fired.
  3. OnRemoveHandler - Called when a delegate is removed from this event.

Each code piece is called advice. Let's write some code on each advice.

public class SimpleEventInterceptionAspect : EventActionInterceptionAspect
{
    public override void OnAddHandler(EventActionInterceptionArgs args) {
        Console.WriteLine("OnAddHandler");
        args.ProceedAddHandler();
    }

    public override void OnInvokeHandler(EventActionInterceptionArgs args) {
        Console.WriteLine("OnInvokeHandler");
        args.ProceedInvokeHandler();
    }

    public override void OnRemoveHandler(EventActionInterceptionArgs args) {
        Console.WriteLine("OnRemoveHandler");
        args.ProceedRemoveHandler();
    }
}

In order for NCop to apply SimpleEventInterceptionAspect as an aspect we need to annotate the OnCodeCompleted event with EventInterceptionAspectAttribute attribute.

using NCop.Mixins.Framework;
using NCop.Composite.Framework;
using NCop.Aspects.Framework;

[TransientComposite]
[Mixins(typeof(CSharpDeveloperMixin))]
public interface IDeveloper
{
    [EventInterceptionAspect(typeof(SimpleEventInterceptionAspect))]
    event Action OnCodeCompleted;

    void Code();
}

An aspect can be placed also on the Mixin's event.

public class CSharpDeveloperMixin : IDeveloper
{
    [EventInterceptionAspect(typeof(SimpleEventInterceptionAspect))]
    public event Action OnCodeCompleted;
 
    public void Code() {
        var onCodeCompleted = OnCodeCompleted;

        Console.WriteLine("C# coding");

        if (onCodeCompleted != null) {
            onCodeCompleted();
        }
    }   
}

The last thing that we have to do is create a CompositeContainer which will handle two things:

  1. Craft the real implementation in runtime.
  2. Act as a Dependency Injection Container that will resolve our type.
using System;
using NCop.Aspects.Framework;
using NCop.Composite.Framework;
using NCop.Mixins.Framework;

class Program
{
    private static void Main(string[] args) {
        IDeveloper developer = null;
        var container = new CompositeContainer();
        Action codeCompletionAction = () => Console.WriteLine("Code Completed");

        container.Configure();
        developer = container.Resolve<IDeveloper>();
        developer.OnCodeCompleted += codeCompletionAction;
        developer.Code();
        developer.OnCodeCompleted -= codeCompletionAction;
    }
}

The expected output should be:
"OnAddHandler"
"C# coding"
"OnInvokeHandler"
"Code Completed"
"OnRemoveHandler
Your end result of the code should be similar to this:

using NCop.Aspects.Framework;
using NCop.Composite.Framework;
using NCop.Mixins.Framework;
using System;

namespace NCop.Samples
{
    [TransientComposite]
    [Mixins(typeof(CSharpDeveloperMixin))]
    public interface IDeveloper
    {
        [EventInterceptionAspect(typeof(SimpleEventInterceptionAspect))]
        event Action OnCodeCompleted;

        void Code();
    }

    public class CSharpDeveloperMixin : IDeveloper
    {
        public event Action OnCodeCompleted;

        public void Code() {
            var onCodeCompleted = OnCodeCompleted;

            Console.WriteLine("C# coding");

            if (onCodeCompleted != null) {
                onCodeCompleted();
            }
        }
    }

    public class SimpleEventInterceptionAspect : EventActionInterceptionAspect
    {
        public override void OnAddHandler(EventActionInterceptionArgs args) {
            Console.WriteLine("OnAddHandler");
            args.ProceedAddHandler();
        }

        public override void OnInvokeHandler(EventActionInterceptionArgs args) {
            Console.WriteLine("OnInvokeHandler");
            args.ProceedInvokeHandler();
        }

        public override void OnRemoveHandler(EventActionInterceptionArgs args) {
            Console.WriteLine("OnRemoveHandler");
            args.ProceedRemoveHandler();
        }
    }

    internal class Program
    {
        private static void Main(string[] args) {
            IDeveloper developer = null;
            var container = new CompositeContainer();
            Action codeCompletionAction = () => Console.WriteLine("Code Completed");

            container.Configure();
            developer = container.Resolve<IDeveloper>();
            developer.OnCodeCompleted += codeCompletionAction;
            developer.Code();
            developer.OnCodeCompleted -= codeCompletionAction;
        }
    }
}