Share via


Watch Out! Overloading Constructors on XAML based Activities

This morning I was refactoring some code and I decided to create a partial class with an overloaded constructor.  When I did this, suddenly everything quit working.  My tests were failing as though the workflow didn’t even run but no exceptions were thrown.  After a while I finally found the problem.  The funny thing is that when I searched the web to see if anybody else had found this problem I found a great blog post written by… me!

More than a year ago I ran into this problem and blogged about it in a generic way here.  But today I just spent an hour with the same problem because I didn’t remember my own blog post.

When you create a XAML based activity, a generated class is created.  For example if I create Workflow1.xaml I also get a generated class Workflow1.g.cs (look for it in \obj\x86\Debug\InProcessTempFiles\Workflow1.g.cs).  This class has a default constructor with a very important job to do.  The job is to load the XAML from the assembly manifest resource stream by calling another generated method InitializeComponent.

 public Workflow1() {
    this.InitializeComponent();
}

If I overload this constructor by creating a partial class I didn’t realize InitializeComponent was no longer being called

 public partial class Workflow1
{
    // Bad constructor - does not initialize component
    public Workflow1(int x, int y)
    {
        InNum = x;
        // You could also do this to fix it
        // InitializeComponent();
    }

    public Workflow1(int x) 
        : this()  // Remember to call this or your XAML activity won't work
    {
        InNum = x;
    }

    public bool ContentLoaded { get { return _contentLoaded; } }
}

What happens if you don’t call InitializeComponent?

Bad things… really bad things…  First off, you would hope that the Workflow Runtime would throw an exception to warn you that your activity is not going to do anything.  Unfortunately nothing will happen.  Here is why.

System.Activities.Activity contains a property named Implementation.

 //
// Summary:
//     Gets or sets the delegate that returns an System.Activities.Activity that
//     contains the execution logic.
//
// Returns:
//     The delegate that contains the execution logic.
[DefaultValue("")]
[XamlDeferLoad(typeof(FuncDeferringLoader), typeof(Activity))]
[Browsable(false)]
[Ambient]
protected virtual Func<Activity> Implementation { get; set; }

If the implementation of your activity is null, your activity does nothing.  When InitializeComponent is called, the implementation is set for you as you can see in the debugger.

image

However, in the case where InitializeComponent is not called because you overloaded the constructor…

image

What does an Activity with a null Implementation do?

Nothing… Apparently the workflow runtime doesn’t mind an activity with a null implementation either.  It doesn’t throw an exception it just silently goes right on by.

What happens to my program then?

You run the workflow but none of the activities contained in the XAML activity run.  You pass inputs, you get your outputs but nothing works (as you can see from the attached example)

SNAGHTML963813

 

 

TestWFPartial.zip