HowTo: Create a Custom Action for an Office SharePoint Designer Workflow – Part 3

 


Ok, so if you’ve been following along up to this point in grand anticipation, this is going to be a happy time for you…we now get to test our custom action.

Step 1 – Create the Workflow


1. Open SPD to the site SPD1


4. Click Next.


5. Name the Step ‘Create Doc Lib’.


6. Select the Actions button and then select ‘Create Fleet Document Library’.


7. Click Name of the doclib and using the Function button, select Current Item and then ‘Customer Name‘.


SPD2 


8. Click Link to site and type in a site name of http://<yourmachineanddomain.com>/FleetCustomers . (the /fleetcustomers sub-site is hard coded in the application)


Your Action should look like this:


SPD3


9. Check the Workflow for Errors. Select Finish.



Step 2 – Testing the Workflow


1. Go back to the site

HowTo: Create a Custom Action for an Office SharePoint Designer Workflow – Part 2

So, in my last post we went through the first steps of what we need to do to create a custom action for Office SharePoint Designer (SPD).  In Part 2, we will add the necessary .ACTION file and make a modification to our web applications web.config file to get our component successfully registered and authorized.


Creating the .ACTION file


1. Create a new text file named CreateFleetDocLib.ACTIONS and save it to:


C:\MSDNBlog\SPD\CreateFleetDocLib\CreateFleetDocLib


We are only saving this file here so it is contained in the same project. It is not compiled with the project.


2. Add the following code to the text file you just created



<?xml version=”1.0″ encoding=”utf-8″?>
<WorkflowInfo>
<Actions Sequential=”then” Parallel=”and”>
<Action Name=”Create Fleet Document Library” ClassName=”CreateFleetDocLib.FleetDocLibActivity” Assembly=”CreateFleetDocLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a796aa76103ee0c2″ AppliesTo=”all” Category=”Labs”>


<RuleDesigner Sentence=”Create fleet document library %1 on %2.”>
<FieldBind Field=”CompanyName” Text=”Name of the doclib” Id=”2″ DesignerType=”TextArea”/>
<FieldBind Field=”Url” Text=”Link to site” DesignerType=”TextArea” Id=”1″/>
</RuleDesigner>


<Parameters>
<Parameter Name=”Url” Type=”System.String, mscorlib” Direction=”In” />
<Parameter Name=”CompanyName” Type=”System.String, mscorlib” Direction=”In” /> </Parameters>


</Action>
</Actions>
</WorkflowInfo>


A couple of things to note here about two of the elements in this file:

<RuleDesigner> – this element represents the text you will see in the actions menu inside of the SPD wizard.

<FieldBind> – this element represents the fields that you will need to fill in in the designer once you have this action item dropped into the designer form.  The important thing here is that the ‘Field’ attribute value needs to be the same as a <Parameter> ‘Name’ attribute in the section below it.  So for example, we have a Field=”CompanyName” and a Parameter Name=”CompanyName”.


3. Browse to the C:\Windows\Assembly directory and right click on the CreateFleetDocLib assembly and select Properties. Copy the Public Key Token to the clipboard.


4. In the CreateFleetDocLib.ACTIONS file, replace the PublicKeyToken with the Public key token you copied to the clipboard.


5. Copy the CreateFleetDocLib.ACTIONS file into the following directory:


                C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\1033\Workflow



Modifying web.config


1. Browse to the directory:


           C:\Inetpub\wwwroot\wss\VirtualDirectories\ <yourmachineanddomain>


2. Open up the web.config file for editing.


3. Add the following to the AuthorizedTypes section of the web.config file.


<authorizedType Assembly=”CreateFleetDocLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a796aa76103ee0c2″ Namespace=”CreateFleetDocLib” TypeName=”*” Authorized=”True” />


4. Save the web.config file


5. Restart IIS (iisreset).

HowTo: Create a Custom Action for an Office SharePoint Designer Workflow – Part 1

Sorry about the long title, but I thought it may help when someone is doing a search for such a topic.  On with the show….


Invariably, if you are using Office SharePoint Designer (SPD) to create workflows, your power users are going to say ‘Hey, I really like this but I want to have an Action that does xyz‘.  Nobody ever seems just satisfied with what we get out of the box, but that’s the beauty of the Microsoft platform, its extensible!


So in part 1, we will talk about the first steps to creating a custom action.


Scenario
Suppose we have a situation where we have a car dealership that caters to customers that purchase fleets of vehicles.  The idea here would be that whenever a new fleet customer wants to sign an order, we would want to take that order form and use it to create a unique site (or document library) for this client.  I’d like to be able to create an action where I could pick from that would allow me to pick up the customers name from the document and use that to create my new document library.


Part 1 – Creating our Custom Action


1. First, we need to setup a sample site in WSS (3.0) or MOSS to use as our base site. Go ahead and create a site http://<yourmachineanddomain.com/FleetCustomers. Create a new document library named ‘Fleet Customer Doc Lib’.  In this document library, create a new custom column (single line of text) named ‘Customer Name’


A custom Action is actually just a custom workflow activity that is registered with the system using an .ACTIONS file, so now we will create a custom activity.


2. Create a new workflow activity library project in Visual Studio 2008 in some location on your machine for example ‘C:\MSDNBlog\SPD‘ Give it the name ‘CreateFleetDocLib’.


3. Rename Activity.cs to FleetDocLibActivity.cs. Open the code view to the activity.


4. Change the base class from SequenceActivity to Activity.


5. Create two Dependency properties (both strings):


















Property Name Data Type Category Description
Url string Input Property Url of base site
CompanyName string Input Property Used as doc lib name

This can also be done by using Insert Snippet > Other > Workflow > Dependency Property – Property.


6. To make sure we require validation on each of these entries (meaning we have to have input), put the following above each of the properties:


[ValidationOption(ValidationOption.Required)]


The code for the dependency properties should look like this:



#region Dep Props


public static DependencyProperty UrlProperty = System.Workflow.ComponentModel.DependencyProperty.Register(“Url”, typeof(string),typeof(FleetDocLibActivity));


[Description(“Base URL of site”)]
[Category(“Input Property”)]
[Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)[ValidationOption(ValidationOption.Required)]
public string Url
{
   
get
   
{
   
return ((string)(base.GetValue
    
(FleetDocLibActivity.UrlProperty)));
   
}


    set
   
{
   
base.SetValue(FleetDocLibActivity.UrlProperty, value);
   
}
}


public static DependencyProperty CompanyNameProperty = System.Workflow.ComponentModel.DependencyProperty.Register(“CompanyName”,typeof(string), typeof(FleetDocLibActivity));

[Description(“Name of the fleet company”)]
[Category(“Input Property”)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[ValidationOption(ValidationOption.Required)]
public string CompanyName
{
  
get
   {
    return ((string)(base.GetValue   
   
(FleetDocLibActivity.CompanyNameProperty)));
    }


   set
  
{
   
base.SetValue(FleetDocLibActivity.CompanyNameProperty, value);
  
}
}



#endregion


7. Add an EventLog variable to the FleetDocLibActivity class along with other variables used for the sites and webs to be accessed.



#region Member Variables


private EventLog _eventLog;


//main site
SPSite mainSite = null;
SPWeb rootweb = null;


//sub site
SPSite subSite = null;
SPWeb subWeb = null;


#endregion


8. Insert the following code inside of the FleetDocLibActivity class (after the constructor)



protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
    //Set up the Event Logging object            
    _eventLog = new EventLog(“Workflow”);
    _eventLog.Source = “SharePoint Workflow”;


    try
    {
        //Send the email                
        CreateDocLib();
    }
    finally
    {
        //Dispose of the Event Logging

        // object         
        _eventLog.Dispose();
    }
    //Indicate the activity has closed            
    return ActivityExecutionStatus.Closed;
}


private void CreateDocLib()
{


    try
    {
        mainSite = new SPSite(Url);
        rootweb = mainSite.OpenWeb();


        //sub site
        subSite = new SPSite(Url + “/FleetCustomers”);
        subWeb = subSite.OpenWeb();


        //get the list collection for the main and sub
        // sites


       SPListCollection lists = subWeb.Lists;
        SPListCollection rootLists = rootweb.Lists;


        //we are going to create a new doc lib in the
        //sub-site, create a new empty template 
        //type then set the type to be a doc library
        SPListTemplateType listTemplateType = new SPListTemplateType();
        listTemplateType = SPListTemplateType.DocumentLibrary;
        lists.Add(CompanyName, “”, listTemplateType);


        SPList taskList = null;

        //look for the tasks lists in the root web
        //also note that SPQuery could be used here 
        foreach (SPList lst in rootLists)
        {
            if (lst.Title.Equals(“Tasks”,
                      StringComparison.InvariantCultureIgnoreCase))
            {
                taskList = lst;
                break;
            }
        }
        if (taskList != null)
        {
            //add a new task item for the administrator
            SPListItem newItem = taskList.Items.Add();
            newItem[“Title”] = “Required completion of Doc Lib ” + CompanyName;
            newItem[“Customer Name”] = CompanyName;
            newItem.Update();
            _eventLog.WriteEntry(“Task assigned to admin”);
        }


        _eventLog.WriteEntry(“Workflow success: Document Library created at: ” + rootweb.Title.ToString());


    }
    catch (System.Exception Ex)
    {
       //Log exceptions in the Event Log                
        _eventLog.WriteEntry(“Workflow Error :” + Ex.Message.ToString(), EventLogEntryType.Information);

    }
    finally
    {


       mainSite.Dispose();
        subSite.Dispose();
        rootweb.Dispose();
        subWeb.Dispose();
    }
} //end CreateDocLib


9.  Add the following using statements to the file:



using System.Diagnostics;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;


10. Add a reference to your project to these (note that you may have to browse for this assemblies) SharePoint assemblies:


Under the .NET tab



Windows SharePoint Services
Windows SharePoint Services Workflow Actions



– If you can’t find the assemblies you can browse directly to C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI\
– Microsoft.SharePoint.dll
– microsoft.sharepoint.WorkflowActions.dll


11. Go into the CreateFleetDocLib project properties and create a new strong named assembly file named FleetLib.snk.


12. Build the assembly and resolve any errors.


13. Using the Visual Studio command prompt, place the library into the GAC by running the following command (NOTE: Don’t forget the double quotes around the path to the assembly):


gacutil /i “C:\MSDNBlog\SPD\CreateFleetDocLib\CreateFleetDocLib\bin\Debug\CreateFleetDocLib.dll”


At this point, we have built the activity that will be used to handle our custom action.  In the Part II, we will create our custom action file.