Presentation is loading. Please wait.

Presentation is loading. Please wait.

AOP in .NET Business Rules + Plumbing = Enterprise Software

Similar presentations


Presentation on theme: "AOP in .NET Business Rules + Plumbing = Enterprise Software"— Presentation transcript:

1 AOP in .NET Business Rules + Plumbing = Enterprise Software
PostSharp AOP in .NET Business Rules + Plumbing = Enterprise Software David Ross W: E:

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 In AOP

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 Compile-time MSIL Injection process
Copyright © by Gael Fraiteur If Postsharp modifies a type’s signature... No Intellisense for a referenced projects that are modified Intellisense for referenced assemblies that are modified

8 PostSharp Weaving Compile time Weaving - LGPL
Automatically if a component references PostSharp.Laos.dll – Default Install configures MSBuild Manual application using an MSBuild task Run time Weaving – GPL/Commercial License Manual via PostSharp.Core.dll Statically modify the assembly just before it is loaded into the domain

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() {
var d = 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); MethodInvocationEventArgs eventArgs = 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(MethodExecutionEventArgs eventArgs) { ActivityRecorder.Record(string.Format("Before {0}", eventArgs.Method)); } public override void OnExit(MethodExecutionEventArgs eventArgs) { ActivityRecorder.Record(string.Format("After {0}", eventArgs.Method)); public override void OnException(MethodExecutionEventArgs eventArgs) {

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; } public int? LikesBeef { get; set; } public int? LikesFish { get; set; } }

17 public override void OnEntry (MethodExecutionEventArgs eventArgs) {
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); q.Postcode = "E14 0AN"; Assert.AreEqual("E14 0AN", q.Postcode); Assert.Throws<ValidationException>(() => q.Postcode = "Hello World"); }

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 Composition 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
public class RequireVirtualMethodsAndProperties : OnMethodBoundaryAspect   { public override bool CompileTimeValidate(MethodBase method)   {              if (!method.IsVirtual) {                 string methodName = method.DeclaringType.FullName + “.” + method.Name;                 var message = new Message(SeverityType.Fatal, “MustBeVirtual”,                     string.Format(“{0} must be virtual”, methodName), GetType().Name);                 MessageSource.MessageSink.Write(message);                 return false;             }             return true;         } }

22 Learn more... Thanks for listening Questions?
Talk’s source Thanks for listening Questions?


Download ppt "AOP in .NET Business Rules + Plumbing = Enterprise Software"

Similar presentations


Ads by Google