Post Sharp Talk


Published on

Introduction to Aspect Orientated Programming in .NET using PostSharp

  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • In AOP
  • Post Sharp Talk

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