Wednesday, February 20, 2008

This is the second 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 a 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 first real step I took: the compound aspect.

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
  • 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.
    Post 1 introduced the project and post 2 introduced PostSharp.

    The Compound aspect

    I have created an attribute class that can be placed on top of other classes, like so:

        /// <summary>
        /// <para>
        /// Attribute that can be used to decorate normal POCO classes with. It is used to start off a post compilation phase
        /// that will modify the IL of the class. After this phase, the class will implement:
        /// <list type="">
        /// <item>INotifyPropertyChanged</item>
        /// <item>IEntityWithChangeTracker</item>
        /// <item>IEntityWithKey</item>
        /// <item>IEntityWithRelationships</item>
        /// </list>
        /// </para>
        /// <para>
        /// It will also place EDMScalarattributes on your properties.
        /// </para>
        /// <para>This results in a type that is completely ready for consumption by the EntityFramework</para>
        /// </summary>
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
        [MulticastAttributeUsage(MulticastTargets.Class, AllowMultiple = false)]
        public sealed class PocoAttribute : CompoundAspect
        {
    ... implementation
        }

    As you can see it inherits from the compound aspect class, from the PostSharp.Laos assembly.

    The compound aspect basically allows you to define other aspects to do the job for you. This is very nice when you want to do more things, but only want to use one aspect.

    By overriding the ProvideAspects method, we can add our other aspects:

      1         public override void ProvideAspects(object element, LaosReflectionAspectCollection collection)
      2         {
      3             // Get the target type.
      4             Type targetType = (Type)element;
      5
      6             // implement the INotifyPropertyChanged interface on the class
      7             collection.AddAspect(targetType, new AddNotifyPropertyChangedInterfaceSubAspect());
      8             // implement the three IPOCO interfaces on the class
      9             collection.AddAspect(targetType, new PocoInterfacesSubAspect());
    10             // inspect the complete class and add EDM scalar attributes to the properties
    11             collection.AddAspect(targetType, new EDMAttributesSubAspect(this.EDMContainerName, Name, NamespaceName, PathToConfigFile));
    12
    13             // iterate the properties
    14             foreach (PropertyInfo property in targetType.UnderlyingSystemType.GetProperties())
    15             {
    16                 if (property.DeclaringType == targetType && property.CanWrite)
    17                 {
    18                     MethodInfo method = property.GetSetMethod();
    19
    20                     if (!method.IsStatic)
    21                     {
    22
    23                         // throw notifypropertychanged events
    24                         collection.AddAspect(method, new OnPropertySetNotifyPropertyChangedSubAspect(property.Name, this.AspectPriority));
    25
    26                         // TODO: possibly refactor to only include edm properties
    27                         // call the changetracker
    28                         collection.AddAspect(method, new OnPropertySetChangeTrackSubAspect(property.Name, this.AspectPriority));
    29                     }
    30                 }
    31             }
    32         }

    As you can see, on line 4 I cast the element parameter to a type. That is the type we have adorned with our attribute (your 'Person' Poco class, for instance). Then, I specify that I want 3 other aspects to work on this type!

    • The AddNotifyPropertyChangedInterfaceSubAspect, will implement the INotifyPropertyChangedInterface. (note: this aspect is added just for simplicity, it has nothing to do with IPoco, so I might remove it).
    • The PocoInterfaceSubAspect, will implement the 3 interfaces (see following post)
    • The EDMAttributesSubAspect, will put EDMScalar attributes on top of our properties, needed by EF to do it's job

    After that, I loop through the properties in our targetType and add aspects to their setters. These will inject methods into the setters to throw the PropertyChanged event and let the EF changetracker know that the property was changed.

    That's all the work this compound aspect does. It just provides aspects to the correct codeblocks. The real work is done inside of these aspects and will be explained in following posts.

    Wednesday, February 20, 2008 1:34:36 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback

    Scott Guthry announces the .Net 3.5 client product Roadmap here.

    Highlights are improved bootstrapping of 3.5 for your client applications and improved cold startup times.

    But the real news for the WPF addicts: the dropshadow and blur bitmap effects will now be hardware accelerated!! That is a big thing. These effects are completely useless at the moment, but if they are hardware accelerated, you will be able to do some great stuff. He also hints at a new effects API and data virtualization support.

    On top of that, he announces that there is a real DataGrid control coming, and my personal favorite: a Calendar/Datepicker control.

    I can easily live without a datagrid, these are so easy to create with the listview, that I don't see a reason to actually build a new control. However, the lack of an official datepicker is in-excusable for enterprise applications. I'm happy to see they are working on it!

    Wednesday, February 20, 2008 12:16:33 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback

    This is an intermezzo from the MVC with WF series. I have added a new sample to the project, which I hope demonstrates the flexibility of using WF.

    The rest of this series can be found here:

  • 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

    It is a simple 4 screen 'wizard' where logic determines that it should skip one screen. Also, when the save button is hit, a popup will show that asks if you are sure. If you are, you will be sent to the first screen, otherwise you will return to your last screen. It has buttons on the left that determine where you can go, as well as 'next' and 'previous' buttons.
    All of this was done with a minimum of code and a maximum of dragging and dropping activities. The whole reason for doing this, is that when you now get a new feature request ("We have a new screen that sits in between the client and adres screen!!!"), using WF it will be dead-simple to add it.

    I have uploaded the executable here, just in case you don't feel like opening up the project and building yourself.
    The application looks like this:

    image

    And when you reach the 'Car' screen, it will look like this:

    image

    Hitting the Save button here:

    image

    A few things to notice about this sample:

    • There are 2 controllers doing their job here:
      • The usersettings controller, with a view on top. It allows you to check a checkbox. Doing so makes you an administrator. Notice how, when you do so, you are able to browse to the 'Role' screen. You see, if you are not an administrator, you are not allowed to enter the role screen.
      • The 'ImportantWizardController', which handles the mainview. It shows a few buttons (Client, Adres, Role and Car) on the left, which will allow you to go to the screens you have already passed. It also shows a previous and next screen button. Finally, it defines a contentpresenter where our subviews will be injected.
    • The buttons react immediately. Go to the Car screen, and then check your checkbox to make yourself Administrator. This means you have the right to visit the Role screen, and it immediately pops up.
    • No code behind. Nowhere. The only codebehind is on the ImportantWizardControl to 'load data' (actually returning an empty client, but you get the drift).
      It felt really cool to build this plumbing without coding.

    Let's look at the steps to produce this application:

    1. I added a Controller project (type workflow), a Domain project (with a few very simple classes), a shell project that will be used to start us up and a view project which holds the views we are going to use:
      image
    2. I created a ClientService and a UserService class which will be classes used by our workflows:
          [Serializable]
          public class UserService
          {
              public bool IsAdministrator { get; set; }

          }
          [Serializable]
          public class ClientService
          {
              public Client CurrentClient { get; set; }

          }
    3. Then the shell was used to inject our main view and also inject a global userservice class:

        1 <Window x:Class="EditLogicShell.Window1"
        2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        4     xmlns:logic="clr-namespace:EditLogicControllers;assembly=EditLogicControllers"      
        5     xmlns:c="clr-namespace:ControllersAdapters;assembly=ControllersAdapters"
        6     Title="Window1" Height="300" Width="300">
        7     <Window.Resources>
        8         <logic:UserService x:Key="globalUserService" />
        9     </Window.Resources>
       10     <StackPanel>
       11         <Border BorderThickness="1" BorderBrush="Black" Background="Beige">
       12             <c:GenericWorkflowAdapter WorkflowController="{x:Type logic:ManageUserSettingsController}" />
       13         </Border>
       14         
       15         <c:GenericWorkflowAdapter WorkflowController="{x:Type logic:ImportantClientWizard}" />
       16     </StackPanel>
       17 </Window>

      Note line 8, where we place a UserService instance in the resources section
      On Line 12 we start our UserSettings controller
      On Line 15, we start our main wizard.

    4. Let's not go into the usersettings controller. It's just too simple. It will inject a view, and set the datacontext to the userservice class. He retrieved that class using the 'RetrieveObjectFromResources' activity.

    5. I then asked our designer (yup, that was me too... could you tell??) to design our individual views. Everywhere the designer knew he had to interact with the system, a command was created in a static class. That class turned out to be like this:

          public static class ImportantWizardInteractions
          {
              public static readonly RoutedUICommand Next;
              public static readonly RoutedUICommand Back;

              public static readonly RoutedUICommand GotoClientScreen;
              public static readonly RoutedUICommand GotoAdresScreen;
              public static readonly RoutedUICommand GotoRoleScreen;
              public static readonly RoutedUICommand GotoCarScreen;

              public static readonly RoutedUICommand Save;
              public static readonly RoutedUICommand SaveYes;
              public static readonly RoutedUICommand SaveNo;


              static ImportantWizardInteractions()
              {
                  Next = new RoutedUICommand("Next", "Next", typeof(ImportantWizardInteractions));
                  Back = new RoutedUICommand("Back", "Back", typeof(ImportantWizardInteractions));

                  GotoClientScreen = new RoutedUICommand("GotoClientScreen", "GotoClientScreen", typeof(ImportantWizardInteractions));
                  GotoAdresScreen = new RoutedUICommand("GotoAdresScreen", "GotoAdresScreen", typeof(ImportantWizardInteractions));
                  GotoRoleScreen = new RoutedUICommand("GotoRoleScreen", "GotoRoleScreen", typeof(ImportantWizardInteractions));
                  GotoCarScreen = new RoutedUICommand("GotoCarScreen", "GotoCarScreen", typeof(ImportantWizardInteractions));

                  Save = new RoutedUICommand("Save", "Save", typeof(ImportantWizardInteractions));
                  SaveYes = new RoutedUICommand("SaveYes", "SaveYes", typeof(ImportantWizardInteractions));
                  SaveNo = new RoutedUICommand("SaveNo", "SaveNo", typeof(ImportantWizardInteractions));


              }
          }
      And on individual screens, the commands were used like this:
                  <Border Background="Beige" BorderThickness="1" BorderBrush="Black" DockPanel.Dock="Left" Width="120" >
                      <ListView>
                          <Label FontWeight="Bold">Previous screens</Label>
                          <Button Command="{x:Static local:ImportantWizardInteractions.GotoClientScreen}">Client</Button>
                          <Button Command="{x:Static local:ImportantWizardInteractions.GotoAdresScreen}">Adres</Button>
                          <Button Command="{x:Static local:ImportantWizardInteractions.GotoRoleScreen}">Role</Button>
                          <Button Command="{x:Static local:ImportantWizardInteractions.GotoCarScreen}">Car</Button>
                      </ListView>
                  </Border>
      (This is the list of buttons that are shown on the left hand side of the screen)
    6. The views were passed to the developer (guess who) and the following state machine was created:
      image 

      Obviously a thing of beauty.

      1. The state initialization will retrieve the userservice, load data, set our maincontent to the mainView and set our next state to clientDetails

      2. The clientdetail has an initialization as well: it will set the datacontext to our customer and inject the ClientView as a datatemplate. Then it waits for only one command: Next. If that is triggered, it will simply move to the AdresDetails State.
        When moving out of a state, the state finalization is triggered, which will remove the view from the resources.
        Note how great it is never to have to think about that cleanup code again, it is always executed when moving out of a state.

      3. The adresDetails state has a few more commands it will listen to. When moving 'Next', a piece of logic is executed:
        image
        There is a declerative rule in the IF/ELSE that goes a little something like this: this.GlobalUserService.IsAdministrator == True
        That rule is automatically put in the rules repository and can be used by others. It determines if the next screen will be the Role screen or the CarDetails screen.

      4. Role is simple.

      5. CarDetails also reacts to the Save-command. When it get's triggered, it will inject our popup into the resources section, and move on to the save state.

      6. The Save state will react to 'SaveYes' and 'SaveNo'. It will remove the popup from the resources, and go to another state.

    7. The views are dead simple, just binding to properties. However, the ImportantWizardMainView does require our attention. It has this definition for our subview:

                  <!-- our subview, uses name: CurrentWizardScreen -->
                  <ContentPresenter 
                  Content="{Binding RelativeSource={RelativeSource FindAncestor, 
                  AncestorType={x:Type local:ImportantWizardMainView}, AncestorLevel=1}, Path=DataContext}" 
                  ContentTemplate="{DynamicResource CurrentWizardScreen}" />


      Apparently, when using the contentTemplate, the datacontext is not inherited. So I have to set it up to react to the changing datacontext of our main screen. So, when the DataContext of ImportantWizardMainView is changed, the Content of our presenter is changed to match it. (Leave comment on how I could do this simpler, if you know how).

    8. Also interesting is that I used a Grid on that view, with two children that overlay eachother. The other child is our popup screen:

              <!-- our popup lives on top of that -->
              <ContentPresenter ContentTemplate="{DynamicResource PopupScreen}" />

      When we set a datatemplate with name Popupscreen, it will be shown on top of our regular screen. I like it!

    I have added a new activity, InjectViewAsDataTemplate. We already had the InjectControllerAsDataTemplate, but there are times you don't want a whole controller.

    I've replaced the original project file with the most recent. It can be found here.
    If you are interested in seeing more about this subject, please leave a short comment!

    kick it on DotNetKicks.com

  • Wednesday, February 20, 2008 11:55:27 AM (Romance Standard Time, UTC+01:00)  #    Comments [3]  |  Trackback
     Tuesday, February 19, 2008

    This is the second 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 a 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 quickly introduces PostSharp, before we move on to the real stuff!

    The full table of contents:

    PostSharp

    The PostSharp home introduces PostSharp as follows:

    PostSharp is a tool that can reduce the number of lines of code and improve its logical decoupling. Therefore its helps you delivering higher stability, cleaner design, and cheaper source code maintenance

    And best of all, PostSharp is free and open source. Yes, even for commercial use

    Basically, it allows you to use attributes on top of code to indicate that after the normal visual studio compilation, PostSharp should do 'something' to the code. That 'something' could be anything you want. The result is a compiled assembly that does more than you would expect from the sourcecode. This is a good thing, when you have 'code noise': code that might be important, but distracts from the real work.

    Code noise could be your logging mechanism, or your transaction mechanism. In my case, I did not want to implement the IPoco interfaces that EntityFramework needs, in order to make my business objects work with EntityFramework. I want my business objects to represent a person, car or whatever, and not have to deal with the data access logic at all.

    The simplest example you can think of, is shown on the frontpage:

    public class SimplestTraceAttribute : OnMethodBoundaryAspect 

      public override void OnEntry( MethodExecutionEventArgs eventArgs) 
      { 
        Trace.TraceInformation("Entering {0}.", eventArgs.Method); 
        Trace.Indent(); 
      } 
      public override void OnExit( MethodExecutionEventArgs eventArgs) 
      { 
        Trace.Unindent(); 
        Trace.TraceInformation("Leaving {0}.", eventArgs.Method); 
      } 
    }

    By adding an [SimplestTrace] attribute on top of your code, you will have instant tracing information, without actually seeing it in your code. The fun thing about PostSharp is, that this code is actually in your assembly after post-compilation, as opposed to other AOP frameworks, that will do it at runtime.

    Laos versus Core
    PostSharp offers a full representation of your code, a bit like reflection. But it can be hard to work with. That is why PostSharp Laos was created. Laos is a 'plugin' on the core functionality that abstracts away most of the hard stuff, and leaves you with ready to implement aspects.

    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.
    (A weaver is a class that will actually inject IL methods into your assembly.)

    When you use Laos, some smart hooks exist to use it's own weaver. That weaver knows how to deal with Laos Aspects. And so, you can use the Laos abstractions without any knowledge about IL or weaving.

    The shown example uses the OnMethodBoundaryAspect, from Laos. The Laos weaver will inject the necessary IL methods on every method (that matches your desire to trace it) to call the OnEntry and the OnExit methods you defined. There are quite a few aspects ready to inherit from. I urge you to look at the documentation to find out which.

    If you were to implement that functionality using the Core library, you would have to inject all the IL yourself. It would however, give you the opportunity to actually inject the Trace calls into the methods, instead of the easier method calls.

    One very interesting aspect that Laos offers, is the CompositionAspect, which allows you to set a specific interface to implement and give an implementation object that is called for every defined method on the interface. I use it for the three IPoco interfaces.

    In short: Laos is a very high-level abstraction that will get you very far. In some cases you need to take it a little further, and you will need Core.

     

    In the next couple of posts, I will show both the Laos aspects and the Core aspect, how they were applied and how they do their job.

    Tuesday, February 19, 2008 12:28:26 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback