I've been working on my presentation and demos for the upcoming SharePoint Conference in Seattle. If you haven't heard of the conference, you are one of the few. It is sold out and there is even a wait list for Microsoft employees to get in. My session is entitled "Enforce Governance by Provisioning Sites with Workflows". It is in the last timeslot on Monday. Stop by and I promise you will see demos that you haven't seen anywhere else. And I should have a few books to give away as well.

For one of my examples, I wanted to create a SharePoint Designer workflow activity that could be used by a site collection owner to control how subsites within their collection are provisioning. Creating a custom activity isn't that hard, but there were a few twists that I had to uncover to get this vision to work. If you have never tried one, there is a Workflow Activity Library project in VS.NET 2005.

This is by no means a complete walkthrough (there is a nice one on MSDN link at the end of this post), but I wanted to highlight some of the major points.

Instead of declaring private fields for your properties use the DependencyProperty class like so:

public static DependencyProperty __ContextProperty = 
       System.Workflow.ComponentModel.DependencyProperty.Register
       ("__Context", typeof(WorkflowContext), typeof
       (SubSiteProvisionActivity));
public static DependencyProperty SiteUrlProperty =
       DependencyProperty.Register("SiteUrl", typeof(string), typeof
       (SubSiteProvisionActivity));
public static DependencyProperty SiteTitleProperty =
       DependencyProperty.Register("SiteTitle", typeof(string), typeof
       (SubSiteProvisionActivity));
       

This is going to allow the user to specify the site title, url, etc. The first one in particular is special. It is going to allow our activity to be aware of the context of the site it is running within. With the dependencies setup, you can create your properties with get/set like so:

[Category("Site Provision Actions"), Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string SiteUrl
{
  get
  {
    return ((string)
           (base.GetValue(SubSiteProvisionActivity.SiteUrlProperty)));
  }
  set
  {
    base.SetValue(SubSiteProvisionActivity.SiteUrlProperty, value);
  }
}

And lastly, override the Execute method to do the work. You will need to make sure this assembly is signed, deployed to the GAC, and registered in the web.config file of your web application. You'll also need an .ACTIONS file that includes the XML markup that describes your activity for SPD.  Here is mine:

<WorkflowInfo>
  <Actions Sequential="then" Parallel="and">
    <Action Name="Create SubSite"
            ClassName="SiteProvisionActivities.SubSiteProvisionActivity"
            Assembly="SiteProvisionActivities, Version=1.0.0.0,
            Culture=neutral, PublicKeyToken=45a2811e9ad438d2"
            AppliesTo="all" Category="Site Provision Actions">
<RuleDesigner Sentence="Create site named %1 at the URL %2 described as %3. Use template %4 with locale %5. %6 use unique Permissions. %7 convert if the site exists. Add to parent's navigation %8 group.">
 <FieldBind Field="SiteTitle" DesignerType="TextArea" Id="1"/>
 <FieldBind Field="SiteUrl" DesignerType="TextArea" Id="2"/>
 <FieldBind Field="SiteDescription" DesignerType="TextArea" Id="3"/>
 <FieldBind Field="SiteTemplate" DesignerType="TextArea" Id="4"/>
 <FieldBind Field="LocaleID" DesignerType="TextArea" Id="5"/>
 <FieldBind Field="UseUniquePermissions" DesignerType="Dropdown" Text="choose"  Id="6">
    <Option Name="Do" Value="True"/>
    <Option Name="Do not" Value="False"/>
 </FieldBind>
 <FieldBind Field="ConvertIfThere" DesignerType="Dropdown" Text="choose"  Id="7">
    <Option Name="Do" Value="True"/>
    <Option Name="Do not" Value="False"/>
  </FieldBind>
  <FieldBind Field="IncludeInParentWebNav" DesignerType="TextArea" Id="8"/>
</RuleDesigner>
      <Parameters>
<Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext, Microsoft.SharePoint.WorkflowActions" Direction="In"/>
<Parameter Name="SiteTitle" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="SiteUrl" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="SiteDescription" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="SiteTemplate" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="LocaleID" Type="System.UInt32, mscorlib" Direction="In" InitialValue="1033" />
<Parameter Name="UseUniquePermissions" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="ConvertIfThere" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="IncludeInParentWebNav" Type="System.String, mscorlib" Direction="In" />
</Parameters>
</Action>
  </Actions>
</WorkflowInfo>

There is a lot here that is too much detail for a blog post. Here are some links
The MSDN article: http://msdn2.microsoft.com/en-us/library/bb629922.aspx
My complete code sample: http://cid-601cfa765e7a6fd3.skydrive.live.com/self.aspx/Public/SiteProvisionActivities.zip

Please Please Please take this code download as a sample only. I made sure it worked well enough for the demonstration. You may definitly want to modify it, add more error handling, and even possibly include RunWithElevatedPrivileges. Finally a nice pic of the end result: