Tuesday, February 26, 2008

Hole crap, this is starting to be a long series!!

This is the seventh of a series about using Workflow Foundation to control your UI Logic in a WPF application. The full table of contents:

Recap

In the first post, the complete solution was presented. I am presenting a solution to use workflow as the controller part in your MVC inspired WPF application. It is inspired on the thought that you do not need complex frameworks, because WPF already gives you great power (routed eventing, resources). So, no IOC is used, no event aggregator etcetera: it's taken care of by WPF and WF, a natural fit.
The solution is very decoupled and I feel it's a great advantage to be able to visual your control logic.
In the previous post, we talked about injecting controllers to manage specific parts of your screen, very cab-alike.

IOC - Inversion of Control

Inversion of Control is a pattern that tries to turn everything upside down when it comes to getting to dependencies. Let's say you have a class, and to do its work it needs a helperclass (maybe a communication service). Instead of having your class create that service explicitly, we can have your class just ask for it and have someone else supply it. This is where Dependency Injection comes from: just state what a class needs to work and have a container 'inject' those dependencies.
Doing it this way makes for a more maintainable application and allows you to better manage the lifetime of helperclasses and services. You might want to get back the same service instance, all the time!

Using a MVC approach to construct your application, you might feel the same need. Maybe you are building an application that allows editing of pieces of information of a customer, for instance, her details, her address, etc.
These pieces are implemented in different views. All the views that belong to that one customer, should use the same instance of the 'customer' object.

Inject and retrieve object into resources - activity

In this system, that is easily done, although possibly more explicitly than many great IOC containers (Windsor, Spring.Net, StructureMap) would like it.

Just have one controller create the object and inject it inside of his resources. Because of the way retrieving resources work, all the controllers that live 'below' this controller (are nested within it), will be able to retrieve it.

image

Here I have dragged in the 'InjectObjectAsResource'Activity, and have bound a public field on my workflow to the 'Service' property of the activity. Well, maybe Service is a bad name, but I just expect you to use it with services most of the time. Also, the activity might better have been called InjectInstanceAsResource, but I guess I didn't.
I used a type as resourcekey this time, instead of a string.

I bet you can figure out how the retrieve activity works ;-)

Tip: since the activity does not know what type of object you want to create, if you let the binding introduce the field or property to your code, it will be typed as object. Just change that to your own type.

The retrieve will work for all controllers that can reach the resource dictionary of the controller that did the inserting. So, that is equivalent to the CAB-term: 'child workitem'.
If you have the need to also be able to share on a global level, just make the inserting happen on the application resources, instead of the adapter resources. Can not be too hard.

Conclusion

I think this mechanism illustrates the way you can use WPF to meet most of your CAB needs. I use it here from a workflow, but that has nothing to do with the core-concept.
I find that the explicit visual call to inject or retrieve, without having to write code to do so, could be beneficial when building systems in a team. There is no need to guess where an object comes from, it is all very much in your face.

Tuesday, February 26, 2008 1:00:22 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback
 Monday, February 25, 2008

This is the sixth of a series about using Workflow Foundation to control your UI Logic in a WPF application. The full table of contents:

Recap

In the first post, the complete solution was presented. I am presenting a solution to use workflow as the controller part in your MVC inspired WPF application. It is inspired on the thought that you do not need complex frameworks, because WPF already gives you great power (routed eventing, resources). So, no IOC is used, no event aggregator etcetera: it's taken care of by WPF and WF, a natural fit.
The solution is very decoupled and I feel it's a great advantage to be able to visual your control logic.
In the previous post, we talked about decoupling through commands.

This time, we will look at how to inject a controller into a subview

The InjectControllerAsDataTemplate activity

It's all very nice and dandy to have one controller manage it's mainview, but what happens if part of that mainview is different, and should be managed by a completely different controller?

Let's look at ModuleView in the BankTeller sample:

<UserControl x:Class="BankTellerViews.ModuleView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <StackPanel Orientation="Horizontal">
        <StackPanel Orientation="Vertical">
            <ContentPresenter ContentTemplate="{DynamicResource userinfo}" />
            <ContentPresenter ContentTemplate="{DynamicResource customerlist}"/>
        </StackPanel>
        <StackPanel Orientation="Vertical">
            <ContentPresenter ContentTemplate="{DynamicResource customerinfo}" />
            <ContentPresenter ContentTemplate="{DynamicResource customersummary}" />
        </StackPanel>
    </StackPanel>
</UserControl>

You can see that ModuleView really only determines the way this screen is build up, but the individual pieces are left empty.

When we open up the ModuleLogic controller, we wish to inject controllers with the same names that we used here:

image

What happens exactly? Well, you selected a controller type, through the convenient typebrowser, and set a specific resource key (in this case, we used a string: userinfo). The adapter is notified by this adapter to do something with it. It will create a datatemplate in code, and just set it as a resource (or replace, if it already exists).

This means that a deeply nested view could easily define a contentpresenter and a higher level controller could inject a controller for it.

Monday, February 25, 2008 4:12:47 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback

This is the fifth of a series about using Workflow Foundation to control your UI Logic in a WPF application. The full table of contents:

  • Workflow as controller: Introducing <M,V,C> where M: ViewModel, V : WPF, C : WF
  • Part II, starting the application, and the adapter
  • Intermezzo: new sample application
  • Part III, your first view
  • Part IV, decoupling view from controller
  • Part V, marshalling commands from WPF to WF
  • Part VI, Injecting a controller in a subview / workspace
  • Part VII, IOC on the cheap: injecting and retrieving objects
  • Part VIII, Broadcasting for all to see

    Whoops, I guess I was a bit over enthusiastic in the previous post, because I already explained the hooking mechanism in enough detail.

    It boils down to registering the adapter as global commandhandlers and when a command reaches it, create a commandMessage and send that to the workflow.

  • Monday, February 25, 2008 3:58:49 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback

    This is the sixth of a series about how to go about using postcompilation in your solutions. You can read it as a tutorial on how to use PostSharp. I am very much new to that framework, but the power it provides could seriously change how you build your applications. While working on the EF contrib project, I had to dive into PostSharp, and I hope to share some of the things I learned along the way.

    This post delves into using the weaver, to do some funky stuff for us!

    The full table of contents:

  • Introducing Entity Framework Contrib- Easy IPoco implementation V 0.1
  • Part II, Postsharp Core versus Postsharp Laos
  • Part III, the compound aspect
  • Part IV, the PocoInterfaceSubaspect (composition aspect)
  • Part V, hooking up the weaver
  • Part VI, the EdmScalarWeaver
    Recap

    We wish to create an attribute that can be placed on top of our ordinary Poco class, that will magically transform it into a class that implements the 3 IPoco interfaces. These are needed by the Entity Framework to do it's work. We will use PostSharp to do this.
    Our previous post talked about the compound attribute and how it goes about implementing interfaces on classes for you.

    We want to put custom attributes on our type that EF needs (the EDM scalar attributes on top of properties and the EDM type attribute that connects your type to a EDM type). Laos does not seem to have a ready-to-use aspect that provides that functionality, so we are going to need to hook into the weaver ourselves! How exciting!
    Thankfully, we can derive from TypeLevelAspectWeaver to make life easy enough.

    In the previous post, we hooked up the weaver, this post we are actually going to do stuff.

    The Implement method

    Our weaver derives from TypeLevelAspectWeaver, and thus can override the Implement() method. I have to do some stuff to get to your config file, using PostSharp to get the Path to the original App.Config. When I have that, I load it, and look at the connectionstring that matches the containername you have supplied the attribute. Then, I use the EntityConnectionBuilder to create a connection string and finally load in the metadata workspace from EDM. With the metadata in hand, I can start looking at the transformation I have to do.

    Setting EDMScalarAttributes

    I recently chatted with Gael (creator of PostSharp) and he assured me that there would be a highlevel method to add attributes to code. In this version of PostSharp, that is not directly possible (hence, the weaver we are using). So, we will do it ourselves.

    First, let's loop through all the properties defined on our supplied businessEntity:

      1             foreach (PropertyDeclaration prop in typeDef.Properties)
      2             {
      3                 EdmProperty memberProperty;
      4 
      5                 // find it as a member
      6                 memberProperty = entityType.Members.SingleOrDefault(edmprop => edmprop.Name.Equals(prop.Name)) as EdmProperty;
      7 
      8                 // it can easily be something else than an edm property
      9                 if (memberProperty != null)
     10                 {
     11                     // it might be a key property. I have not yet found a better way to determine if it is a keymember or not. This seems wastefull
     12                     prop.CustomAttributes.Add(
     13                         CreatePropertyAttribute(memberProperty,
     14                         (entityType.KeyMembers.SingleOrDefault(edmprop => edmprop.Name.Equals(prop.Name)) != null)));
     15 
     16                     continue;
     17                 }
    18             }

    I use a bit of Linq to check if this a propety is a key, and call my CreatePropertyAttribute method:

      1         CustomAttributeDeclaration CreatePropertyAttribute(EdmProperty edmProperty, bool IsKeyProperty)
      2         {
      3             CustomAttributeDeclaration attr = new CustomAttributeDeclaration(edmScalarPropertyAttribute);
      4 
      5             // nullable
      6             attr.NamedArguments.Add(
      7                 new MemberValuePair(MemberKind.Property,
      8                     0,
      9                     "IsNullable",
     10                     new SerializedValue(
     11                         SerializationType.GetSerializationType(this.module.FindType(typeof(bool), BindingOptions.Default)),
     12                         edmProperty.Nullable)
     13                         ));
     14 
     15             // since we need to set the ordinal, take care to set this property last!
     16             if (IsKeyProperty)
     17             {
     18                 attr.NamedArguments.Add(
     19                     new MemberValuePair(MemberKind.Property,
     20                         1,
     21                         "EntityKeyProperty",
     22                         new SerializedValue(
     23                             SerializationType.GetSerializationType(this.module.FindType(typeof(bool), BindingOptions.Default)),
     24                             true)
     25                             ));
     26             }
     27 
     28             return attr;
    29         }

    As you can see, it get's a little bit more complicated. We need to add a custom attribute, but to get it, we need to have a constructor for the attribute. I already have it cached: at line 3 the cached IMethod is given to the PostSharp CustomAttributeDecaration class. I got to the ctor like this:

                edmScalarPropertyAttribute = module.FindMethod(typeof(EdmScalarPropertyAttribute).GetConstructor(System.Type.EmptyTypes), BindingOptions.Default);
    

    We use PostSharp to find the constructor in the module.

    With the constructor, we can create a customAttributeDeclaration and from there we can add namedArguments. Note, that here again, we use PostSharp to find types for us. Kind of confusing, but it does provide a consistent way to do things. You could use it to call your own methods as well (!).

    I do the same for the attribute that needs to be placed on the complete type, and we are ready!

    Default values

    In the EF designer, you have the ability to specify default values for properties. I needed to mimic this functionality for this project, so I got to work. It seemed quite simple, because I could get to the fields without a problem. However, fields are initialized in the ctor of your type (thank you reflector). So more work was needed.

    First, I wanted to reuse this weaver, and wanted the weaver to add IL methods in the constructor. To do that, I implemented the ITypeLevelAdvice interface and added this line to the end of the implement():

                // make sure this class is called to weave
    
                this.Task.TypeLevelAdvices.Add(this);

    Implementing the ITypeLevelAdvice gives us the opportunity to supply some  information about what we want to do exactly:

            #region ITypeLevelAdvice Members
    
            public JoinPointKinds JoinPointKinds { get { return JoinPointKinds.AfterInstanceInitialization; } }
    
            public TypeDefDeclaration Type { get { return (TypeDefDeclaration)this.TargetElement; } }
    
            #endregion
    
            #region IAdvice Members
    
            public int Priority
    
            {
    
                get { return 0; }
    
            }
    
            public bool RequiresWeave(PostSharp.CodeWeaver.WeavingContext context)
    
            {
    
                return true;
    
            }
    
            #endregion

    As you can see, I want to use the AfterInstanceInitialization joinpoint. In other words, I want to be able to weave code, at that moment.

    What to weave?? I know everything about my businessentity, but I only know which properties need default values. So I want to come up with some basic rules about which field belongs to a certain propertyname:

      1             #region set default values. not yet emitting the instruction, but waiting for the Weave method
    
      2             foreach (FieldDefDeclaration field in typeDef.Fields)
    
      3             {
    
      4                 // we have to make concessions: we do not know how to find the field with the property exactly
    
      5                 EdmProperty memberProperty;
    
      6 
    
      7                 // find it as a member
    
      8                 // the rules: the field must match the ending of the propertyname. So underscore is okay
    
      9                 memberProperty = entityType.Members.SingleOrDefault(edmprop => field.Name.EndsWith(edmprop.Name, StringComparison.OrdinalIgnoreCase) ) as EdmProperty;
    
     10 
    
     11                 // in case that didn't match, try the autogenerated fieldname
    
     12                 if (memberProperty == null)
    
     13                 {
    
     14                     memberProperty = entityType.Members.SingleOrDefault(edmprop => (field.Name.IndexOf("<" + edmprop.Name + ">") == 0)) as EdmProperty;
    
     15                 }
    
     16 
    
     17                 // if this field belongs to a edm property, we can check for it's default value
    
     18                 if (memberProperty != null)
    
     19                 {
    
     20                     FieldsNeedingDefaultValue.Add(field, memberProperty.Default);
    
     21                 }
    
     22 
    
     23             }  
    24             #endregion

    I use two rules: if the field ends with the same name as the property, then this field belongs to that property. Another rule is, to look at the naming scheme that the compiler uses when it generates auto properties: <Propertyname>_k_backingfield;. Since that is how we will most likely use this whole project, I want to also support that.
    I build up a default value dictionary that I use in a later stadium.

    The weave method will be called when our joinpoint has been reached.

      1         public void Weave(PostSharp.CodeWeaver.WeavingContext context, InstructionBlock block)
    
      2         {
    
      3             foreach (FieldDefDeclaration field in FieldsNeedingDefaultValue.Keys)
    
      4             {
    
      5                 object value = FieldsNeedingDefaultValue[field];
    
      6 
    
      7                 if (value == null)
    
      8                     continue;
    
      9 
    
     10                 // the context is the ctor because we only use the joinpoint AfterinstanceInitialization
    
     11                 InstructionSequence sequence = context.Method.MethodBody.CreateInstructionSequence();
    
     12                 block.AddInstructionSequence(sequence, NodePosition.Before, null);
    
     13                 context.InstructionWriter.AttachInstructionSequence(sequence);
    
     14                 InstructionWriter writer = context.InstructionWriter;
    
     15 
    
     16                 if(value is int)
    
     17                 {
    
     18                             writer.EmitInstruction(OpCodeNumber.Nop);
    
     19                             writer.EmitInstruction(OpCodeNumber.Ldarg_0);
    
     20                             writer.EmitInstructionInt32(OpCodeNumber.Ldc_I4, (int)value );
    
     21                             writer.EmitInstructionField(OpCodeNumber.Stfld, field);                }
    
     22                 else if (value is string)
    
     23                 {
    
     24                             writer.EmitInstruction(OpCodeNumber.Nop);
    
     25                             writer.EmitInstruction(OpCodeNumber.Ldarg_0);
    
     26                             writer.EmitInstructionString(OpCodeNumber.Ldstr, (string)value);
    
     27                             writer.EmitInstructionField(OpCodeNumber.Stfld, field);                }
    
     28                 else
    
     29                 {
    
     30                     // TODO: implement other value types
    
     31                     throw new NotImplementedException(String.Format("No IL default implemented for type {0}", value.GetType()));
    
     32                 }
    
     33 
    
     34                 writer.DetachInstructionSequence(true);
    
     35             }
    
     36 
    
    37         }

    Again, Gael has assured me that a highlevel functionality will be created to easily set default values. I do not like to work with a big IF statement to inject different IL instructions per type, but that's it for now....

    I just use reflector, in IL viewing mode, to see how I should initialize a certain type, and off we go.

     

    This is the end of this series. I hope you enjoyed it.

    The following things still have to be done:

    • PostSharp can now be installed without using the GAC. I think people feel more at ease just using an external assembly, so I will change the EFContrib project to support this.
    • Relationships and complex types need to be supported
    • Obviously, the other default values need to be supported.

    I'll keep you updated on how that progresses!
    I hope this series has given you some ideas on how to use postcompiling in your own project. Let it make your life easier and your code cleaner.

  • Monday, February 25, 2008 3:56:01 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback
     Friday, February 22, 2008

    Scott Guthrie talks about silverlight 2.0 and it is looking to be exactly what I hoped it would be. It seems they are really aiming for enabling RIA applications, but cross platform, cross browser.

    The big announcement is the inclusion of built-in controls. It was a big disappointment to me that they were not included in silverlight 1.0 or 1.1, but they are included now!

    My take on this is that it will revolutionize the way we build software. As you might know, I've been involved in creating a big RIA application with xbap. Although it was great, we did not have a very good story on the use of the 'browser'. I was reminded time and time again that it was weird to use the browser, while it was not cross platform or even cross browser. We had good reasons to go for xbap none the less, but I'm looking forward to seeing what we can do with Silverlight 2.0.

    Friday, February 22, 2008 9:28:46 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback

    I sometimes do it, but don't like to do it too often. But this one, I just want to archive here so I can always find it: Beatriz has just released a great ready-to-use drag and drop library. She has also written a terrific blog post about it here, that shows the steps she took to achieve it.

    I just ran the project and it performs well, has insertion adorners and even allows dragging and dropping within the same list. Good stuff!

    Friday, February 22, 2008 1:54:19 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback

    This is the fourth of a series about using Workflow Foundation to control your UI Logic in a WPF application. The full table of contents:

  • Workflow as controller: Introducing <M,V,C> where M: ViewModel, V : WPF, C : WF
  • Part II, starting the application, and the adapter
  • Intermezzo: new sample application
  • Part III, your first view
  • Part IV, decoupling view from controller
  • Part V, marshalling commands from WPF to WF
  • Part VI, Injecting a controller in a subview / workspace
  • Part VII, IOC on the cheap: injecting and retrieving objects
  • Part VIII, Broadcasting for all to see
    Recap

    In the first post, the complete solution was presented. I am presenting a solution to use workflow as the controller part in your MVC inspired WPF application. It is inspired on the thought that you do not need complex frameworks, because WPF already gives you great power (routed eventing, resources). So, no IOC is used, no event aggregator etcetera: it's taken care of by WPF and WF, a natural fit.
    The solution is very decoupled and I feel it's a great advantage to be able to visual your control logic.
    In the previous post, I talked about the various ways to show a view, and actually already talked about the decoupling mechanism: commands.

  • I'm very lucky to have received some good comments from Wekemf about tight coupling. I urge you to read those comments and maybe chime in.

    In this post I will not return on that subject, but will quickly address two important activities that help in configuring your system quickly: the SetMainContent activity and the SetDataContext activity and sending WPF commands to WF's HandleCommand.

    SetMainContent activity

    A controller adapter is a normal WPF contentcontrol. It has the job to participate in the visual tree on behalf of our workflow controller class. To actually attach a view to it, we need to set it's content property.

    As shown in the previous post, you can just set on in xaml yourself, but it's more logical to let the workflow decide on the view. Ofcourse, the best approach is totally up to you.

    I usually use the stateinitalization activity to set up a view for us. I drag in the SetMainContent activity, and choose a type from the references assemblies.
    If it weren't for this step, the controller assembly would not need a reference to the view assembly at all. I found it very cool to be able to select a type with the typebrowser and just have it show up.

    The typebrowser is located in an assembly I have put in the externalAssemblies folder. It is a project, not started by me. The code did not work when I got my hands on it, but I managed to fix it by using a hammer. Check out this post to learn more about this great design-time experience!

    If you have a business need to decouple even further, you would need to adjust the SetMainContent activity, and instead of sending a real Type, send a string key or whatever. Then you would create some mapping functionality to map that key to the actual view.

    When the adapter get's notified by the SetMainContentMessage that it needs to set a content, it will just create the view (using reflection) and place it as it's own content.

    SetDataContext activity

    I do not like MVP at all, where the presenter talks back to the view directly (using an interface or something). I feel it's way too 'pushy' and way too much work. I believe in databinding (especially WPF bindings, I think Microsoft got it right this time). You view should just bind to your domain objects. In many cases, it's better to create a wrapper for the domainobjects, so you have the opportunity to supply some shortcut properties or view specific stuff: you might have a list of products, and you want the view to display the sum of the prices. That is a great opportunity for the viewmodel to expose a 'Sum' property that the view can simply bind to.

    The object that is used as a ViewModel should live with the controller who will be able to communicate with it.
    I usually create an internal public class, simply called ViewModel and have the controller inject that class with domain objects.

    The Set DataContext activity is very similar to the SetMainContent activity, in that it let's the adapter know it has to set a datacontext on itself.
    You configure the SetDataContext activity simply by choosing a field or property of your controller.

    In small sample applications, I have used the 'invoking' event, to hook up some code that actually initializes the ViewModel object.

    Sending WPF commands to the Workflow: HandleCommandActivity

    The HandleCommandActivity is really what makes using the solution so easy. I have blogged about it already extensively, and I will just summarize here:

    Workflow has a difficult communication story. You need to define your incoming and outgoing calls in an ExternalDataExchangeService. Then you have to hook up events in your workflow to listen to incoming calls/events. It is not possible to listen to the same events in two different states, without using the very difficult CorrelationTechnique.

    This is not necessary for our usage. I have created the HandleCommand activity to just listen to a queue with a specific name. That name is defined by the command we are listening to. So, if you want your workflow to react when you send it the string 'workflowRules', you would just drag in the HandleCommand and configure the Command property to read 'workflowRules'. No need to setup a special event for it.

    The commandService class has a PostCommand method, that you can call to put a message on the queue. That's all there is to it.

    So, when we receive a WPF command, we cast it to a RoutedUI command. The commandname is used to form a SimpleCommandMessage which can be used as input to the PostCommand method.

      1         #region command sinks
      2         private void CmdExecuted(object sender, ExecutedRoutedEventArgs e)
      3         {
      4             string commandname = (e.Command as RoutedUICommand).Name;
      5
      6             PostCommand(commandname, e.Parameter);
      7
      8         }
      9
    10         private void PostCommand(string commandname, object Parameter)
    11         {
    12             if (implementedCommands.Contains(commandname))
    13             {
    14                 commandSvc.PostCommand(new SimpleCommandMessage(instance.InstanceId, commandname, Parameter));
    15             }
    16         }
    17
    18         private void CmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
    19         {
    20             string commandName = (e.Command as RoutedUICommand).Name;
    21
    22             if (implementedCommands.Contains(commandName))
    23             {
    24                 e.CanExecute = commandSvc.CanExecute(new SimpleCommandMessage(instance.InstanceId, commandName));
    25             }
    26         }
    27
    28         #endregion

    As you can see, I first check if the workflow even implements such a command. If not, it would be too expensive to send it to the workflow.
    Also, check out the CmdCanExecute method. It actually makes it possible for the workflow to put rules on the HandleCommand activity that are used to figure out if a command can be executed. For instance, if you are not authorized to do something, the command was never in CanExecute, so the button that hooks up to it was always dimmed!

    I hope that clears up some questions. Let me know what you think!

    Friday, February 22, 2008 11:24:20 AM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback

    This is the fifth of a series about how to go about using postcompilation in your solutions. You can read it as a tutorial on how to use PostSharp. I am very much new to that framework, but the power it provides could seriously change how you build your applications. While working on the EF contrib project, I had to dive into PostSharp, and I hope to share some of the things I learned along the way.

    This post introduces the weaver, that will do exciting stuff for us.

    The full table of contents:

  • Introducing Entity Framework Contrib- Easy IPoco implementation V 0.1
  • Part II, Postsharp Core versus Postsharp Laos
  • Part III, the compound aspect
  • Part IV, the PocoInterfaceSubaspect (composition aspect)
  • Part V, hooking up the weaver
  • Part VI, the EdmScalarWeaver
    Recap

    We wish to create an attribute that can be placed on top of our ordinary Poco class, that will magically transform it into a class that implements the 3 IPoco interfaces. These are needed by the Entity Framework to do it's work. We will use PostSharp to do this.
    Our previous post talked about the compound attribute and how it goes about implementing interfaces on classes for you.

    This post will look at how we are going to hook up a weaver to do more complex stuff, not directly supported by the provided Laos aspects.

    But first I want to clear up a statement I made here: 'I found it wildly confusing the first time I came across the two parts of postsharp. Laos is such a high-level abstraction, that you use it quite differently from Core. In the latter, you have to spinup your own weaver, in Laos you do not ever see a weaver. '
    It is not true that you do not ever see a weaver when using Laos. I should have been more c