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