SlideShare a Scribd company logo
1 of 22
PostSharp AOP in .NET Business Rules + Plumbing = Enterprise Software David Ross W: www.pebblesteps.com E: willmation@gmail.com
Application Concerns Core Crosscutting Non-functional Requirements Model needs to provide capability for many different layers At layer boundaries Logging Validation Security Data marshalling Functional Requirements Domain/Object Model Business Logic
Crosscutting Concerns – Plumbing Logging/Monitoring/Alerting Type safety (Beyond value types int, string) Validation/Enforcement Security Authorisation/Authentication Data Binding INotifyPropertyChanged DependencyProperties Transactions Concurrency  - Locking
Aspects - Reduce noise in source Move plumbing out of source, but keep behaviour the same Advice The duplicated plumbing code we are removing Typically under 30 lines of code Behaviour that is injected at a join point Join points Places within the code where the Aspect is inserted Examples Entry/Exit of a method or property Class’s Type Definition
Aspects Lingo Point cut Locates Join Points to apply advice Filter  driven– Automatic injection Find all Methods, of type Setter, in all classes where Namespace equals “Application.Entities” Attribute driven – Manual injection
Aspects Lingo Weaving Process of injecting functionality back into a component Can be performed by Text post processor – Magic comments can replaced by code Proxy container – Uses decorator pattern/hooks to allow code to be inserted Binary manipulation - Modifying assemblies - by replacing and injecting IL code
Compile-time MSIL Injection process Copyright © by Gael Fraiteur If Postsharp modifies a type’s signature... ,[object Object]
Intellisense for referenced assemblies that are modified,[object Object]
Example class public class Demo 	{ public Demo() 		{ ActivityRecorder.Record("In constructor"); 		} public void Foo() 		{ ActivityRecorder.Record("In Foo"); 		} public void StaticFoo() 		{ ActivityRecorder.Record("In StaticFoo"); 		} 	}
[Test]  public void Verify_Aspect_Called_On_Method_Invocation() { vard = new Demo (); d.Foo(); d.StaticFoo(); ActivityRecorder.AssertActivityOccured("In constructor"); ActivityRecorder.AssertActivityOccured("Calling Void Foo()"); ActivityRecorder.AssertActivityOccured("In Foo"); ActivityRecorder.AssertActivityOccured("Calling Void StaticFoo()"); ActivityRecorder.AssertActivityOccured("In StaticFoo"); ActivityRecorder.AssertNoMoreActivities(); }
Method Invocation - Aspect [Serializable] public class ExampleOnMethodInvocationAspect : OnMethodInvocationAspect { public override void OnInvocation(MethodInvocationEventArgs context) { ActivityRecorder.Record(string.Format("Calling {0}", 	context.Delegate.Method.Replace(“~”, “”));     // Do I want to continue?? context.Proceed();   } }
Code after Injection private void ~Foo() { ActivityRecorder.Record("In Foo"); } [DebuggerNonUserCode, CompilerGenerated] public void Foo(){ Delegate delegateInstance = new ~PostSharp~Laos~Implementation.~delegate~0(this.~Foo); MethodInvocationEventArgseventArgs = new MethodInvocationEventArgs(delegateInstance, null); 	~PostSharp~Laos~Implementation.SkillsMatter.PostSharp.Aspects. ExampleOnMethodInvocationAspect~1.OnInvocation(eventArgs); }
Filter based Point Cut  [assembly: ExampleOnMethodInvocationAspect (AttributeTargetAssemblies = "SkillsMatter.PostSharp", AttributeTargetTypes = "SkillsMatter.PostSharp.OnMethodInvocation.*")] Very simple to apply changes to all business objects in the solution with a single filter...
On Boundary Invocation - Aspect [Serializable] public class ExampleOnMethodBoundaryAspect : OnMethodBoundaryAspect{ public override void OnEntry(MethodExecutionEventArgseventArgs) { ActivityRecorder.Record(string.Format("Before {0}",  eventArgs.Method)); 	} public override void OnExit(MethodExecutionEventArgseventArgs) { ActivityRecorder.Record(string.Format("After {0}", eventArgs.Method)); 	} public override void OnException(MethodExecutionEventArgseventArgs) { ActivityRecorder.Record(string.Format("After {0}", eventArgs.Method)); 	} }
[Test]  public void Verify_Aspect_Called_On_Method_Boundary() { var e = new Demo(); e.Foo(); e.StaticFoo(); ActivityRecorder.AssertActivityOccured("Before Void .ctor()"); ActivityRecorder.AssertActivityOccured("In constructor"); ActivityRecorder.AssertActivityOccured("After Void .ctor()"); ActivityRecorder.AssertActivityOccured("Before Void Foo()"); ActivityRecorder.AssertActivityOccured("In Foo"); ActivityRecorder.AssertActivityOccured("After Void Foo()"); ActivityRecorder.AssertActivityOccured("Before Void StaticFoo()"); ActivityRecorder.AssertActivityOccured("In StaticFoo"); ActivityRecorder.AssertActivityOccured("After Void StaticFoo()"); ActivityRecorder.AssertNoMoreActivities(); }
Manual Point Cut public class FoodQuestionaire 	{ 		[RegularExpressionValidator("^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$")] public string Postcode { get; set; } 		[RangeValidator(0, 5)] public int? LikesDiary { get; set; } 		[RangeValidator(0, 5)] public int? LikesBeef { get; set; } 		[RangeValidator(0, 5)] public int? LikesFish { get; set; } 	}
public override void OnEntry 	(MethodExecutionEventArgseventArgs)  { 	if (!eventArgs.Method.Name.StartsWith(“set_")) return; int value = (int)args[0]; 	if (value < LowerBoundary  || value > UpperBoundary) 		throw new ValidationException 		("Value must be between " +  LowerBoundary + " and “ + UpperBoundary); base.OnEntry(eventArgs); }
[Test] public void RangeTest() { FoodQuestionaire q = new FoodQuestionaire(); q.LikesBeef = 5; Assert.AreEqual(5, q.LikesBeef); Assert.Throws<ValidationException>(() => q.LikesBeef = 100); Assert.Throws<ValidationException>(() => q.LikesBeef = -3); Assert.AreEqual(5, q.LikesBeef); q.Postcode = "E14 0AN"; Assert.AreEqual("E14 0AN", q.Postcode); Assert.Throws<ValidationException>(() => q.Postcode 		= "Hello World"); Assert.AreEqual("E14 0AN", q.Postcode); }
On Method Boundary can be used for... How long did a method take to execute? Resource Management – Create resource before a method is called and release afterwards Transactions – Commit/Rollback as required Concurrency – Mutual Exclusion around code
Other Aspects Implement Method Aspect  Replace a method’s content with the advice in the aspect Useful for modifying 3rd party components Composition Aspect Allows an interface/state to be injected into a component Used to simulate multiple inheritance Examples include Adding .NET Win Form data binding to a POCO Adding Entity Framework interfaces to a POCO
Breaking the Build All NHibernate  methods must be virtual – Davy Brion publicclassRequireVirtualMethodsAndProperties  : OnMethodBoundaryAspect  {   publicoverrideboolCompileTimeValidate(MethodBase method)    {              if (!method.IsVirtual)  {                 stringmethodName = method.DeclaringType.FullName +  “.” 			+ method.Name;                   var message = newMessage(SeverityType.Fatal, “MustBeVirtual”,                     string.Format(“{0} must be virtual”, methodName), GetType().Name);                 MessageSource.MessageSink.Write(message);                   returnfalse;             }             returntrue;         } }
Learn more... Talk’s source code @ www.pebblesteps.com http://www.postsharp.org/ http://davybrion.com/blog/category/postsharp/ http://www.codeplex.com/ValidationAspects http://www.eclipse.org/aspectj/doc/released/progguide/ Thanks for listening Questions?

More Related Content

What's hot

Unit tests in node.js
Unit tests in node.jsUnit tests in node.js
Unit tests in node.jsRotem Tamir
 
Introduction to nsubstitute
Introduction to nsubstituteIntroduction to nsubstitute
Introduction to nsubstituteSuresh Loganatha
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: RebirthJohn De Goes
 
Errors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 librariesErrors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 librariesPVS-Studio
 
Advanced Ruby
Advanced RubyAdvanced Ruby
Advanced Rubyalkeshv
 
Object Oreinted Approach in Coldfusion
Object Oreinted Approach in ColdfusionObject Oreinted Approach in Coldfusion
Object Oreinted Approach in Coldfusionguestcc9fa5
 
Javascript Secrets - Front in Floripa 2015
Javascript Secrets - Front in Floripa 2015Javascript Secrets - Front in Floripa 2015
Javascript Secrets - Front in Floripa 2015Fernando Daciuk
 
Sony C#/.NET component set analysis
Sony C#/.NET component set analysisSony C#/.NET component set analysis
Sony C#/.NET component set analysisPVS-Studio
 
The Ring programming language version 1.10 book - Part 97 of 212
The Ring programming language version 1.10 book - Part 97 of 212The Ring programming language version 1.10 book - Part 97 of 212
The Ring programming language version 1.10 book - Part 97 of 212Mahmoud Samir Fayed
 
Towards the Cloud: Event-driven Architectures in PHP
Towards the Cloud: Event-driven Architectures in PHPTowards the Cloud: Event-driven Architectures in PHP
Towards the Cloud: Event-driven Architectures in PHPBenjamin Eberlei
 
10reasons
10reasons10reasons
10reasonsLi Huan
 
What’s new in .NET
What’s new in .NETWhat’s new in .NET
What’s new in .NETDoommaker
 
Getting to Grips with SilverStripe Testing
Getting to Grips with SilverStripe TestingGetting to Grips with SilverStripe Testing
Getting to Grips with SilverStripe TestingMark Rickerby
 
OPERATING OVERLOADING IN VHDL
OPERATING OVERLOADING IN VHDLOPERATING OVERLOADING IN VHDL
OPERATING OVERLOADING IN VHDLBLESSYDAISE PAUL
 
Xenogenetics for PL/SQL - infusing with Java best practices
Xenogenetics for PL/SQL - infusing with Java best practicesXenogenetics for PL/SQL - infusing with Java best practices
Xenogenetics for PL/SQL - infusing with Java best practicesLucas Jellema
 
Test Driven Development With Python
Test Driven Development With PythonTest Driven Development With Python
Test Driven Development With PythonSiddhi
 
The Ring programming language version 1.5 book - Part 14 of 31
The Ring programming language version 1.5 book - Part 14 of 31The Ring programming language version 1.5 book - Part 14 of 31
The Ring programming language version 1.5 book - Part 14 of 31Mahmoud Samir Fayed
 

What's hot (19)

Unit tests in node.js
Unit tests in node.jsUnit tests in node.js
Unit tests in node.js
 
Introduction to nsubstitute
Introduction to nsubstituteIntroduction to nsubstitute
Introduction to nsubstitute
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: Rebirth
 
Errors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 librariesErrors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 libraries
 
Advanced Ruby
Advanced RubyAdvanced Ruby
Advanced Ruby
 
Rspec 101
Rspec 101Rspec 101
Rspec 101
 
Object Oreinted Approach in Coldfusion
Object Oreinted Approach in ColdfusionObject Oreinted Approach in Coldfusion
Object Oreinted Approach in Coldfusion
 
Javascript Secrets - Front in Floripa 2015
Javascript Secrets - Front in Floripa 2015Javascript Secrets - Front in Floripa 2015
Javascript Secrets - Front in Floripa 2015
 
Sony C#/.NET component set analysis
Sony C#/.NET component set analysisSony C#/.NET component set analysis
Sony C#/.NET component set analysis
 
The Ring programming language version 1.10 book - Part 97 of 212
The Ring programming language version 1.10 book - Part 97 of 212The Ring programming language version 1.10 book - Part 97 of 212
The Ring programming language version 1.10 book - Part 97 of 212
 
Towards the Cloud: Event-driven Architectures in PHP
Towards the Cloud: Event-driven Architectures in PHPTowards the Cloud: Event-driven Architectures in PHP
Towards the Cloud: Event-driven Architectures in PHP
 
10reasons
10reasons10reasons
10reasons
 
What’s new in .NET
What’s new in .NETWhat’s new in .NET
What’s new in .NET
 
Agile mobile
Agile mobileAgile mobile
Agile mobile
 
Getting to Grips with SilverStripe Testing
Getting to Grips with SilverStripe TestingGetting to Grips with SilverStripe Testing
Getting to Grips with SilverStripe Testing
 
OPERATING OVERLOADING IN VHDL
OPERATING OVERLOADING IN VHDLOPERATING OVERLOADING IN VHDL
OPERATING OVERLOADING IN VHDL
 
Xenogenetics for PL/SQL - infusing with Java best practices
Xenogenetics for PL/SQL - infusing with Java best practicesXenogenetics for PL/SQL - infusing with Java best practices
Xenogenetics for PL/SQL - infusing with Java best practices
 
Test Driven Development With Python
Test Driven Development With PythonTest Driven Development With Python
Test Driven Development With Python
 
The Ring programming language version 1.5 book - Part 14 of 31
The Ring programming language version 1.5 book - Part 14 of 31The Ring programming language version 1.5 book - Part 14 of 31
The Ring programming language version 1.5 book - Part 14 of 31
 

Viewers also liked

Test Infected Presentation
Test Infected PresentationTest Infected Presentation
Test Infected Presentationwillmation
 
Behaviour Driven Development V 0.1
Behaviour Driven Development V 0.1Behaviour Driven Development V 0.1
Behaviour Driven Development V 0.1willmation
 
10 Insightful Quotes On Designing A Better Customer Experience
10 Insightful Quotes On Designing A Better Customer Experience10 Insightful Quotes On Designing A Better Customer Experience
10 Insightful Quotes On Designing A Better Customer ExperienceYuan Wang
 
Learn BEM: CSS Naming Convention
Learn BEM: CSS Naming ConventionLearn BEM: CSS Naming Convention
Learn BEM: CSS Naming ConventionIn a Rocket
 
How to Build a Dynamic Social Media Plan
How to Build a Dynamic Social Media PlanHow to Build a Dynamic Social Media Plan
How to Build a Dynamic Social Media PlanPost Planner
 

Viewers also liked (6)

Mpi.Net Talk
Mpi.Net TalkMpi.Net Talk
Mpi.Net Talk
 
Test Infected Presentation
Test Infected PresentationTest Infected Presentation
Test Infected Presentation
 
Behaviour Driven Development V 0.1
Behaviour Driven Development V 0.1Behaviour Driven Development V 0.1
Behaviour Driven Development V 0.1
 
10 Insightful Quotes On Designing A Better Customer Experience
10 Insightful Quotes On Designing A Better Customer Experience10 Insightful Quotes On Designing A Better Customer Experience
10 Insightful Quotes On Designing A Better Customer Experience
 
Learn BEM: CSS Naming Convention
Learn BEM: CSS Naming ConventionLearn BEM: CSS Naming Convention
Learn BEM: CSS Naming Convention
 
How to Build a Dynamic Social Media Plan
How to Build a Dynamic Social Media PlanHow to Build a Dynamic Social Media Plan
How to Build a Dynamic Social Media Plan
 

Similar to AOP in .NET with PostSharp

Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy codeShriKant Vashishtha
 
Embedded Typesafe Domain Specific Languages for Java
Embedded Typesafe Domain Specific Languages for JavaEmbedded Typesafe Domain Specific Languages for Java
Embedded Typesafe Domain Specific Languages for JavaJevgeni Kabanov
 
SystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummarySystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummaryAmal Khailtash
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimizedWoody Pewitt
 
Groovy Introduction - JAX Germany - 2008
Groovy Introduction - JAX Germany - 2008Groovy Introduction - JAX Germany - 2008
Groovy Introduction - JAX Germany - 2008Guillaume Laforge
 
Spring AOP @ DevClub.eu
Spring AOP @ DevClub.euSpring AOP @ DevClub.eu
Spring AOP @ DevClub.euarsenikum
 
Scrum Gathering 2012 Shanghai_工程实践与技术卓越分会场:how to write unit test for new cod...
Scrum Gathering 2012 Shanghai_工程实践与技术卓越分会场:how to write unit test for new cod...Scrum Gathering 2012 Shanghai_工程实践与技术卓越分会场:how to write unit test for new cod...
Scrum Gathering 2012 Shanghai_工程实践与技术卓越分会场:how to write unit test for new cod...LetAgileFly
 
Micro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicateMicro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicateKiev ALT.NET
 
Apex Testing and Best Practices
Apex Testing and Best PracticesApex Testing and Best Practices
Apex Testing and Best PracticesJitendra Zaa
 
Best practices for crafting high quality PHP apps (ScotlandPHP 2018)
Best practices for crafting high quality PHP apps (ScotlandPHP 2018)Best practices for crafting high quality PHP apps (ScotlandPHP 2018)
Best practices for crafting high quality PHP apps (ScotlandPHP 2018)James Titcumb
 
Security Testing
Security TestingSecurity Testing
Security TestingKiran Kumar
 
Best practices for crafting high quality PHP apps (PHP South Africa 2018)
Best practices for crafting high quality PHP apps (PHP South Africa 2018)Best practices for crafting high quality PHP apps (PHP South Africa 2018)
Best practices for crafting high quality PHP apps (PHP South Africa 2018)James Titcumb
 
CiklumJavaSat_15112011:Alex Kruk VMForce
CiklumJavaSat_15112011:Alex Kruk VMForceCiklumJavaSat_15112011:Alex Kruk VMForce
CiklumJavaSat_15112011:Alex Kruk VMForceCiklum Ukraine
 
Navigating the xDD Alphabet Soup
Navigating the xDD Alphabet SoupNavigating the xDD Alphabet Soup
Navigating the xDD Alphabet SoupDror Helper
 
Crafting Quality PHP Applications: an overview (PHPSW March 2018)
Crafting Quality PHP Applications: an overview (PHPSW March 2018)Crafting Quality PHP Applications: an overview (PHPSW March 2018)
Crafting Quality PHP Applications: an overview (PHPSW March 2018)James Titcumb
 
RIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWTRIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWTMichael Galpin
 
using python module: doctest
using python module: doctestusing python module: doctest
using python module: doctestmitnk
 

Similar to AOP in .NET with PostSharp (20)

Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
Embedded Typesafe Domain Specific Languages for Java
Embedded Typesafe Domain Specific Languages for JavaEmbedded Typesafe Domain Specific Languages for Java
Embedded Typesafe Domain Specific Languages for Java
 
SystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummarySystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features Summary
 
Nativescript angular
Nativescript angularNativescript angular
Nativescript angular
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimized
 
Groovy Introduction - JAX Germany - 2008
Groovy Introduction - JAX Germany - 2008Groovy Introduction - JAX Germany - 2008
Groovy Introduction - JAX Germany - 2008
 
Google guava
Google guavaGoogle guava
Google guava
 
Spring AOP @ DevClub.eu
Spring AOP @ DevClub.euSpring AOP @ DevClub.eu
Spring AOP @ DevClub.eu
 
Scrum Gathering 2012 Shanghai_工程实践与技术卓越分会场:how to write unit test for new cod...
Scrum Gathering 2012 Shanghai_工程实践与技术卓越分会场:how to write unit test for new cod...Scrum Gathering 2012 Shanghai_工程实践与技术卓越分会场:how to write unit test for new cod...
Scrum Gathering 2012 Shanghai_工程实践与技术卓越分会场:how to write unit test for new cod...
 
Micro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicateMicro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicate
 
Apex Testing and Best Practices
Apex Testing and Best PracticesApex Testing and Best Practices
Apex Testing and Best Practices
 
Best practices for crafting high quality PHP apps (ScotlandPHP 2018)
Best practices for crafting high quality PHP apps (ScotlandPHP 2018)Best practices for crafting high quality PHP apps (ScotlandPHP 2018)
Best practices for crafting high quality PHP apps (ScotlandPHP 2018)
 
Linq intro
Linq introLinq intro
Linq intro
 
Security Testing
Security TestingSecurity Testing
Security Testing
 
Best practices for crafting high quality PHP apps (PHP South Africa 2018)
Best practices for crafting high quality PHP apps (PHP South Africa 2018)Best practices for crafting high quality PHP apps (PHP South Africa 2018)
Best practices for crafting high quality PHP apps (PHP South Africa 2018)
 
CiklumJavaSat_15112011:Alex Kruk VMForce
CiklumJavaSat_15112011:Alex Kruk VMForceCiklumJavaSat_15112011:Alex Kruk VMForce
CiklumJavaSat_15112011:Alex Kruk VMForce
 
Navigating the xDD Alphabet Soup
Navigating the xDD Alphabet SoupNavigating the xDD Alphabet Soup
Navigating the xDD Alphabet Soup
 
Crafting Quality PHP Applications: an overview (PHPSW March 2018)
Crafting Quality PHP Applications: an overview (PHPSW March 2018)Crafting Quality PHP Applications: an overview (PHPSW March 2018)
Crafting Quality PHP Applications: an overview (PHPSW March 2018)
 
RIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWTRIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWT
 
using python module: doctest
using python module: doctestusing python module: doctest
using python module: doctest
 

AOP in .NET with PostSharp

  • 1. PostSharp AOP in .NET Business Rules + Plumbing = Enterprise Software David Ross W: www.pebblesteps.com E: willmation@gmail.com
  • 2. Application Concerns Core Crosscutting Non-functional Requirements Model needs to provide capability for many different layers At layer boundaries Logging Validation Security Data marshalling Functional Requirements Domain/Object Model Business Logic
  • 3. Crosscutting Concerns – Plumbing Logging/Monitoring/Alerting Type safety (Beyond value types int, string) Validation/Enforcement Security Authorisation/Authentication Data Binding INotifyPropertyChanged DependencyProperties Transactions Concurrency - Locking
  • 4. Aspects - Reduce noise in source Move plumbing out of source, but keep behaviour the same Advice The duplicated plumbing code we are removing Typically under 30 lines of code Behaviour that is injected at a join point Join points Places within the code where the Aspect is inserted Examples Entry/Exit of a method or property Class’s Type Definition
  • 5. Aspects Lingo Point cut Locates Join Points to apply advice Filter driven– Automatic injection Find all Methods, of type Setter, in all classes where Namespace equals “Application.Entities” Attribute driven – Manual injection
  • 6. Aspects Lingo Weaving Process of injecting functionality back into a component Can be performed by Text post processor – Magic comments can replaced by code Proxy container – Uses decorator pattern/hooks to allow code to be inserted Binary manipulation - Modifying assemblies - by replacing and injecting IL code
  • 7.
  • 8.
  • 9. Example class public class Demo { public Demo() { ActivityRecorder.Record("In constructor"); } public void Foo() { ActivityRecorder.Record("In Foo"); } public void StaticFoo() { ActivityRecorder.Record("In StaticFoo"); } }
  • 10. [Test] public void Verify_Aspect_Called_On_Method_Invocation() { vard = new Demo (); d.Foo(); d.StaticFoo(); ActivityRecorder.AssertActivityOccured("In constructor"); ActivityRecorder.AssertActivityOccured("Calling Void Foo()"); ActivityRecorder.AssertActivityOccured("In Foo"); ActivityRecorder.AssertActivityOccured("Calling Void StaticFoo()"); ActivityRecorder.AssertActivityOccured("In StaticFoo"); ActivityRecorder.AssertNoMoreActivities(); }
  • 11. Method Invocation - Aspect [Serializable] public class ExampleOnMethodInvocationAspect : OnMethodInvocationAspect { public override void OnInvocation(MethodInvocationEventArgs context) { ActivityRecorder.Record(string.Format("Calling {0}", context.Delegate.Method.Replace(“~”, “”)); // Do I want to continue?? context.Proceed(); } }
  • 12. Code after Injection private void ~Foo() { ActivityRecorder.Record("In Foo"); } [DebuggerNonUserCode, CompilerGenerated] public void Foo(){ Delegate delegateInstance = new ~PostSharp~Laos~Implementation.~delegate~0(this.~Foo); MethodInvocationEventArgseventArgs = new MethodInvocationEventArgs(delegateInstance, null); ~PostSharp~Laos~Implementation.SkillsMatter.PostSharp.Aspects. ExampleOnMethodInvocationAspect~1.OnInvocation(eventArgs); }
  • 13. Filter based Point Cut [assembly: ExampleOnMethodInvocationAspect (AttributeTargetAssemblies = "SkillsMatter.PostSharp", AttributeTargetTypes = "SkillsMatter.PostSharp.OnMethodInvocation.*")] Very simple to apply changes to all business objects in the solution with a single filter...
  • 14. On Boundary Invocation - Aspect [Serializable] public class ExampleOnMethodBoundaryAspect : OnMethodBoundaryAspect{ public override void OnEntry(MethodExecutionEventArgseventArgs) { ActivityRecorder.Record(string.Format("Before {0}", eventArgs.Method)); } public override void OnExit(MethodExecutionEventArgseventArgs) { ActivityRecorder.Record(string.Format("After {0}", eventArgs.Method)); } public override void OnException(MethodExecutionEventArgseventArgs) { ActivityRecorder.Record(string.Format("After {0}", eventArgs.Method)); } }
  • 15. [Test] public void Verify_Aspect_Called_On_Method_Boundary() { var e = new Demo(); e.Foo(); e.StaticFoo(); ActivityRecorder.AssertActivityOccured("Before Void .ctor()"); ActivityRecorder.AssertActivityOccured("In constructor"); ActivityRecorder.AssertActivityOccured("After Void .ctor()"); ActivityRecorder.AssertActivityOccured("Before Void Foo()"); ActivityRecorder.AssertActivityOccured("In Foo"); ActivityRecorder.AssertActivityOccured("After Void Foo()"); ActivityRecorder.AssertActivityOccured("Before Void StaticFoo()"); ActivityRecorder.AssertActivityOccured("In StaticFoo"); ActivityRecorder.AssertActivityOccured("After Void StaticFoo()"); ActivityRecorder.AssertNoMoreActivities(); }
  • 16. Manual Point Cut public class FoodQuestionaire { [RegularExpressionValidator("^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$")] public string Postcode { get; set; } [RangeValidator(0, 5)] public int? LikesDiary { get; set; } [RangeValidator(0, 5)] public int? LikesBeef { get; set; } [RangeValidator(0, 5)] public int? LikesFish { get; set; } }
  • 17. public override void OnEntry (MethodExecutionEventArgseventArgs) { if (!eventArgs.Method.Name.StartsWith(“set_")) return; int value = (int)args[0]; if (value < LowerBoundary || value > UpperBoundary) throw new ValidationException ("Value must be between " + LowerBoundary + " and “ + UpperBoundary); base.OnEntry(eventArgs); }
  • 18. [Test] public void RangeTest() { FoodQuestionaire q = new FoodQuestionaire(); q.LikesBeef = 5; Assert.AreEqual(5, q.LikesBeef); Assert.Throws<ValidationException>(() => q.LikesBeef = 100); Assert.Throws<ValidationException>(() => q.LikesBeef = -3); Assert.AreEqual(5, q.LikesBeef); q.Postcode = "E14 0AN"; Assert.AreEqual("E14 0AN", q.Postcode); Assert.Throws<ValidationException>(() => q.Postcode = "Hello World"); Assert.AreEqual("E14 0AN", q.Postcode); }
  • 19. On Method Boundary can be used for... How long did a method take to execute? Resource Management – Create resource before a method is called and release afterwards Transactions – Commit/Rollback as required Concurrency – Mutual Exclusion around code
  • 20. Other Aspects Implement Method Aspect  Replace a method’s content with the advice in the aspect Useful for modifying 3rd party components Composition Aspect Allows an interface/state to be injected into a component Used to simulate multiple inheritance Examples include Adding .NET Win Form data binding to a POCO Adding Entity Framework interfaces to a POCO
  • 21. Breaking the Build All NHibernate methods must be virtual – Davy Brion publicclassRequireVirtualMethodsAndProperties : OnMethodBoundaryAspect  { publicoverrideboolCompileTimeValidate(MethodBase method)   {              if (!method.IsVirtual) {                 stringmethodName = method.DeclaringType.FullName + “.” + method.Name;                   var message = newMessage(SeverityType.Fatal, “MustBeVirtual”,                     string.Format(“{0} must be virtual”, methodName), GetType().Name);                 MessageSource.MessageSink.Write(message);                   returnfalse;             }             returntrue;         } }
  • 22. Learn more... Talk’s source code @ www.pebblesteps.com http://www.postsharp.org/ http://davybrion.com/blog/category/postsharp/ http://www.codeplex.com/ValidationAspects http://www.eclipse.org/aspectj/doc/released/progguide/ Thanks for listening Questions?

Editor's Notes

  1. In AOP