-
Notifications
You must be signed in to change notification settings - Fork 7
Function Boundary Aspect
Let's change a bit the type that we've created in the Atom Composite
example.
We will change the method from a subroutine (method that does not returns a value) to a function.
public interface IDeveloper
{
/// From
void Code();
}
public interface IDeveloper
{
/// To
string Code();
}
Let's implement the new Mixin
.
using NCop.Mixins.Framework;
using NCop.Composite.Framework;
[TransientComposite]
[Mixins(typeof(CSharpDeveloperMixin))]
public interface IDeveloper
{
string Code();
}
public class CSharpDeveloperMixin : IDeveloper
{
public string Code() {
return "C# coding";
}
}
We want to apply the aspect on the Code
function.
The function has a string return value, therefore we need to create a new aspect that is derived from OnFunctionBoundaryAspect`.
public class StopwatchMethodBoundaryAspect : OnFunctionBoundaryAspect<string>
{
private readonly Stopwatch stopwatch = null;
public StopwatchMethodBoundaryAspect() {
stopwatch = new Stopwatch();
}
}
If the Code
function accepted one parameter of type string then our aspect would derive from OnFunctionBoundaryAspect<string, string>
using NCop.Mixins.Framework;
using NCop.Composite.Framework;
[TransientComposite]
[Mixins(typeof(CSharpDeveloperMixin))]
public interface IDeveloper
{
string Code(string language);
}
public class StopwatchMethodBoundaryAspect : OnFunctionBoundaryAspect<string, string>
{
}
When you derive from a boundary aspect you'll get the option to insert pieces of code in several points in the program (a.k.a join points):
- OnEntry - Called before the execution of the method.
- OnSuccess - Called when the execution of the method is done executing and there were no exceptions.
- OnException - Called when an unhandled exception has been raised.
- OnExit - Called after the execution of the method.
Each code piece is called advice. Let's write some code on each advice.
public class StopwatchMethodBoundaryAspect : OnFunctionBoundaryAspect<string>
{
private readonly Stopwatch stopwatch = null;
public StopwatchMethodBoundaryAspect() {
stopwatch = new Stopwatch();
}
public override void OnEntry(FunctionExecutionArgs<string> args) {
Console.WriteLine("{0} OnEntry", args.Method.Name);
stopwatch.Restart();
}
public override void OnException(FunctionExecutionArgs<string> args) {
Console.WriteLine("{0} OnException", args.Method.Name);
}
public override void OnExit(FunctionExecutionArgs<string> args) {
Console.WriteLine("{0} OnExit", args.Method.Name);
}
public override void OnSuccess(FunctionExecutionArgs<string> args) {
stopwatch.Stop();
Console.WriteLine("Elapsed Ticks: {0}", stopwatch.ElapsedTicks);
Console.WriteLine("Return value: {0}", args.ReturnValue);
}
}
In order for NCop to apply StopwatchMethodBoundaryAspect
as an aspect we need to annotate the Code
function with OnMethodBoundaryAspectAttribute
attribute.
using NCop.Mixins.Framework;
using NCop.Composite.Framework;
using NCop.Aspects.Framework;
[TransientComposite]
[Mixins(typeof(CSharpDeveloperMixin))]
public interface IDeveloper
{
[OnMethodBoundaryAspect(typeof(StopwatchMethodBoundaryAspect))]
string Code();
}
An aspect can be placed also on the Mixin's function.
public class CSharpDeveloperMixin : IDeveloper
{
[OnMethodBoundaryAspect(typeof(StopwatchMethodBoundaryAspect))]
public string Code() {
return "C# coding";
}
}
The last thing that we have to do is create a CompositeContainer
which will handle two things:
- Craft the real implementation in runtime.
- Act as a Dependency Injection Container that will resolve our type.
using System;
using NCop.Mixins.Framework;
using NCop.Composite.Framework;
using NCop.Aspects.Framework;
class Program
{
static void Main(string[] args) {
string result = null;
IDeveloper developer = null;
var container = new CompositeContainer();
container.Configure();
developer = container.Resolve<IDeveloper>();
result = developer.Code();
Console.WriteLine(result);
}
}
The expected output should be:
"Code OnEntry"
"Elapsed Ticks: [Number of ticks]"
"Code OnExit"
"C# coding"
Your end result of the code should be similar to this:
using System;
using NCop.Aspects.Framework;
using NCop.Mixins.Framework;
using NCop.Composite.Framework;
using System.Diagnostics;
namespace NCop.Samples
{
[TransientComposite]
[Mixins(typeof(CSharpDeveloperMixin))]
public interface IDeveloper
{
[OnMethodBoundaryAspect(typeof(StopwatchMethodBoundaryAspect))]
string Code();
}
public class CSharpDeveloperMixin : IDeveloper
{
public string Code() {
return "C# coding";
}
}
public class StopwatchMethodBoundaryAspect : OnFunctionBoundaryAspect<string>
{
private readonly Stopwatch stopwatch = null;
public StopwatchMethodBoundaryAspect() {
stopwatch = new Stopwatch();
}
public override void OnEntry(FunctionExecutionArgs<string> args) {
Console.WriteLine("{0} OnEntry", args.Method.Name);
stopwatch.Restart();
}
public override void OnException(FunctionExecutionArgs<string> args) {
Console.WriteLine("{0} OnException", args.Method.Name);
}
public override void OnExit(FunctionExecutionArgs<string> args) {
Console.WriteLine("{0} OnExit", args.Method.Name);
}
public override void OnSuccess(FunctionExecutionArgs<string> args) {
stopwatch.Stop();
Console.WriteLine("Elapsed Ticks: {0}", stopwatch.ElapsedTicks);
Console.WriteLine("Return value: {0}", args.ReturnValue);
}
}
class Program
{
static void Main(string[] args) {
string result = null;
IDeveloper developer = null;
var container = new CompositeContainer();
container.Configure();
developer = container.Resolve<IDeveloper>();
result = developer.Code();
Console.WriteLine(result);
}
}
}