serge's profileSerge Luca (Sharepoint M...PhotosBlogLists Tools Help

Blog


    November 20

    Step by Step Tutorial. Creating Workflows for Windows Sharepoint Services and MOSS2007 (part 10/20)

     

     

    image

    Step 10/20. Reuse, Modify and Debug a Sharepoint Designer workflow in Visual Studio  

     

    By Serge Luca

     

    image

     

    1.Scenario

    Microsoft Sharepoint Designer 2007 is a very interesting tool that allows developers and users to create workflows  running in Sharepoint 2007 without writing code.
    The workflows generated by Sharepoint Designer cannot be debugged and reused in another site unless we import it in Visual Studio.Net.This tutorial will show you how to achieve this.

    I assume that your have the correct setup for creating workflows for Sharepoint .

    2.Hands-on

    • Create a team site. By default a task list ("tasks") is generated.
    • Create another task list and call it “Issues”.
    • Now start Sharepoint Designer and open your web site (Menu “File-Open Site”).
    Let’s create a very simple workflow that will copy a task list item from the "Task" list to the "Issues" list if the Title column of the record contains the word “problem”.
    • In Sharepoint Designer, start the Menu “File”-“New Workflow”; keep the default workflow name and select the list you want the workflow to be associated with: Task; unselect the option “allow this workflow to be manually started from an item” and select the two others.

     

    image

     

    Click on the Next button of the form and the Workflow Designer will show up :

     

    image

    Click on the Conditions button and select the option Compare Tasks field.

    image

    In the condition, click on the “field” hyperlink and select Title in the combobox.
    In the condition, click on the “value” hyperlink and type “problem” (without the quotes).
    In the condition, click on the “equals” hyperlink and select “contains”.


     

    image

    In the Action, select “Copy List Item”.

    image

    Click on the Finish button of the form; Sharepoint Designer will  generate the xoml code (which is not xaml activated code !!!) , it will compile the code ( xaml activated code must not be compiled) and it will associate the workflow to the corresponding list.

    3.Testing the workflow

    Add a new item in the task list: set the Title to “problem in Belgium”: since the Task's Title column contains the word “problem”, it will be copied to the Issues list by the workflow .

    4.Importing the workflow in Visual Studio

    In Sharepoint Designer, go to the Workflows folder, select Workflow1 and right click on “Publish Selected Files” : 
     

    image

    Select the option “File System” (specify a file location) :

    image

    Click on OK. The following files will be generated  at the selected location:

    image

    Rename the file Workflow1.xoml.rules to Workflow1.rules.

    In our specific case, the .rules file contains the test that will check if the title column contains the word “problem”; this test is expressed in the  CodeDom language.

    Create a new Sharepoint Workflow project  that will host the generated files ; name it MySPWorkflow :

     

    image

    Add the files Workflow1.rules and Workflow1.xoml into the new project and delete Workflow1.cs :

    image

    Click on Workflow1.xoml and the workflow will show up in the Workflow Designer :

    image

    • The first activity (ID1) is a Microsoft.Sharepoint.WorkflowActions.OnWorkflowActivated activity and makes the link between the workflow and the Sharepoint context (like the list and the list item among many other things).
    • The activity ID6 is a Microsoft.Sharepoint.WorkflowActions.CopyItemActivity .
      The workflow itself is derived from Microsoft.SharePoint.WorkflowActions.RootWorkflowActivityWithData which is derived from SequentialWorkflowActivity.
    • The following code shows the real content code of Workflow1.xoml:

     

    <ns0:RootWorkflowActivityWithData x:Class="Microsoft.SharePoint.Workflow.ROOT" x:Name="ROOT" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ns0="clr-namespace:Microsoft.SharePoint.WorkflowActions;Assembly=Microsoft.SharePoint.WorkflowActions, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">

          <ns0:RootWorkflowActivityWithData.WorkflowFields>

                <ns0:WorkflowDataField Name="__list" Type="System.String" />

                <ns0:WorkflowDataField Name="__item" Type="System.Int32" />

                <ns0:WorkflowDataField Name="__context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext" />

                <ns0:WorkflowDataField Name="__initParams" Type="Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties" />

                <ns0:WorkflowDataField Name="__workflowId" Type="System.Guid" />

          </ns0:RootWorkflowActivityWithData.WorkflowFields>

          <ns0:OnWorkflowActivated WorkflowProperties="{ActivityBind ROOT,Path=__initParams}" x:Name="ID1" EventName="OnWorkflowActivated">

                <ns0:OnWorkflowActivated.CorrelationToken>

                      <wf0:CorrelationToken Name="refObject" OwnerActivityName="ROOT" xmlns:wf0="http://schemas.microsoft.com/winfx/2006/xaml/workflow" />

                </ns0:OnWorkflowActivated.CorrelationToken>

          </ns0:OnWorkflowActivated>

          <IfElseActivity x:Name="ID4" Description="Step 1">

                <IfElseBranchActivity x:Name="ID3">

                      <IfElseBranchActivity.Condition>

                            <RuleConditionReference ConditionName="__Rule_ID3" />

                      </IfElseBranchActivity.Condition>

                      <ns0:CopyItemActivity ListId="{}{7DC0CBDB-1A73-4A9A-8F7C-7FF3EFC3807B}" x:Name="ID6" Overwrite="False" ToListId="{}{A3EBF037-9BAA-49DC-A8B6-87A8795DA41F}" __Context="{ActivityBind ROOT,Path=__context}" ListItem="{ActivityBind ROOT,Path=__item}" />

                </IfElseBranchActivity>

          </IfElseActivity>

    </ns0:RootWorkflowActivityWithData>

     

    5.Xoml code

    1.We can notice that this not what Workflow Foundation afficionados called “xaml activated” code which is xaml code that can  run on the fly without having to be compiled. This code must be compiled: indeed the x:class attribute provides the compiler with a class name for the workflow :

     

    <ns0:RootWorkflowActivityWithData x:Class="Microsoft.SharePoint.Workflow.ROOT" x:Name="ROOT"

    The workflow itself is an activity named Root and derived from the class RootWorkflowActivityWithData.

    image 

    2. According to the Sharepoint sdk, the RootWorkflowActivityWithData class has a WorkflowFields  property which is a collection of key-object pairs where the key is a string (describing the property name) and the object a type (the type of the property); this is an handy way to dynamically add properties of any type to a class.

    image

    The following  xoml fragment shows how Sharepoint Designer feeds this WorkflowFields property :

     

    <ns0:RootWorkflowActivityWithData>

          <ns0:RootWorkflowActivityWithData.WorkflowFields>

                <ns0:WorkflowDataField Name="__list" Type="System.String" />

                <ns0:WorkflowDataField Name="__item" Type="System.Int32" />

                <ns0:WorkflowDataField Name="__context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext" />

                <ns0:WorkflowDataField Name="__initParams" Type="Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties" />

                <ns0:WorkflowDataField Name="__workflowId" Type="System.Guid" />

          </ns0:RootWorkflowActivityWithData.WorkflowFields>

     

    • __list: the list Guid.
    • __item: the index of the ListItem.
    • __context: a Microsoft.SharePoint.WorkflowActions.WorkflowContext which is a class that will encapsulate some elements of the well known SPWorkflowActivationProperties (stored in the __initParams field). In our example, the instance of this class will be used internally by the CopyItem activity to provide some necessary information like the SPWeb for instance.
    • __initParams: a Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties ; this class provides many information like the SPWeb, the SPList, the SPListItem etc…

    The reason for using a WorkflowContext instead of directly a SPWorkflowActivationProperties object is not clear here.

    Another way to visualize these properties is to select the workflow object in the workflow designer and to display the associated property page :

    image

    Here is what we get if we click on the collection:

    image

    This will initialize the informations the CopyItemActity needs (see later).

     

    Now, let’s take a look at the CopyItemActivity properties :

    image

    In order to copy one ListItem to an other list, the CopyItemActivity needs some informations:

    1.       The original list Guid: ListId property .

    2.       The destination list Guid: ToListid property.

    3.       The list item index: ListItem property ;  databinding from the __item property of the workflow.

    4.       The SPWeb object : __Context property; databinding from the __context member of the workflow.

     

    6.Deployment and test of the workflow

     

    We will deploy the workflow as a feature, therefore we need to modify the install.bat file :

    1.       Sign the project

    2.       Retrieve the strong name

    3.       In  install.bat , replace http://localhost with your site collection url

    4.       in install.bat, replace myFeature with the assembly name

    5.       run install.bat

    6.       test the workfow

    7.Error

    This workflow generates an error :

    image

    8.Fault Handler

    To get more detailed information about this error, it is necessary to add a Fault Activity (equivalent of a catch block) and to log it.

    Select the workflow in the (Visual Studio) Workflow Designer, click on the lower left side of the Designer and click on the Fault Handler:

    image

    Another view of the Workflow Designer will show up:

    image

    Drag and drop a FaultHandler activity from the Workflow Foundation toolbox into  fautlHandlersActivity1 :

    image

    In the property page of this last activity select the FaultType property by browsing the mscrolib assembly:

    image

    Select System.Exception:

    image

    Now we will log the StackTrace into the workflow history log: drag and drop a LogHistoryList activity into the handler (if you don’t find this activity drag and drop the microsoft.Sharepoint.WorkflowAction.dll assembly to a new Visual Studio toolbox tab) :

    image

    Select the logToHistoryListActivity1 and set its HistoryOutcome property to the stack trace value of faultHandlerActivity1:

    image

    image

    Rebuild the solution , redeploy (install.bat) and test the workflow.

    The trace will show up in the workflow status :

    image

    Remove the activity ID2 : this activity (class ApplyActivation) is the source of the error.

    Let’s Click on the ID1 activity to generate the code behind and paste the following code in the generated handler:

            private void ID1_Invoked(object sender, ExternalDataEventArgs e)

            {

                __context = new WorkflowContext();

                __context.Initialize(__initParams);

                __list = __initParams.List.ToString();

                __item = __initParams.ItemId;

                __workflowId = __initParams.WorkflowId;

            }

     

    Recompile the workflow, and test it.

    9.Debugging our workflow

    Reset the web server, refresh the web site, open the project in Visual Studio, set a breakpoint in ID1_Invoked and attach the browser to the w3wp.exe host:

    image

    Invoke the workflow by changing a value in the title property, you should hit your breakpoint.

    Reusing the workflow in another site

    The good news is that the CopyItemActivity can use both list Guid or list name.

    Select its property page and set the ListId and ToListId properties respectively  to “Tasks” and “Issues”:

    image

    Recompile the workflow, deploy and test it to make sure it works again ;-)

    The same workflow can be reused in another site if the appropriate list (“Tasks” and “Issues”) are present.

     

    10.Modify the .rules files

    The condition that evaluates if the list item contains the word "problem" is stored in a rule file which is compiled with the application (in another post I will show you how to store and retrieve it dynamically from a database, and how a user can create this rules). The rules generated by Sharepoint Designer are rather cryptic.

    Select the activity ID3 in the Workflow designer and click on the Condition property in the property page:

    image

    Select the Expression property, you’ll see something like this:

    image

    Replace the whole content of this windows with the following code :

    image

    That’s it ! Recompile, deploy and test the application .

     


    This hands-on training is the property of U2U and may not be organized in class or in group without the prior written permission of U2U. Should you wish to organize this hands-on training in your company or institution, please contact U2U first to enter into a licence agreement. Each trainer or teacher using this hands-on training should have a licence agreement. Please ask your trainer or U2U whether he or she has entered into a licence agreement with U2U.

    The hyperlink "www.u2u.be/msdna" to this hands-on training may be placed on your website for free, on the condition that the name and the logo of U2U are clearly mentioned in the reference. Please send us a mail containing the link to the web page our reference is used on.