Problem mixing OOTB SPD WFAs and Custom WFAs

2019-08-10 03:25发布

问题:

I'm using MOSS (SharePoint 2007 Enterprise), 32-bit, SP2.

I've been noticing some odd problems with Custom Workflow Activities which I've developed and am using in SharePoint Designer (SPD) workflows. These actions seem to work correctly, but don't "play nice" with the rest of the workflow (specifically, the root issue was posted at: Timing concerns with Custom WF Activity changing permissions , since that hasn't gotten any responses I've been digging deeper...)

To help pin down the problem, I've developed a very simple test, which I will outline in detail below, and am noticing even more odd behavior with this test, which is what I'll get into first...

So, at the end of this test I've got a simple SPD WF which I can start manually on a list I created for this test, which contains a Single Line of Text field/column named "TextField". The WF contains 1 step which performs 4 actions:

  1. Set Field to Value (uses my custom WFA to assign "1" to the TextField column)
  2. Log "Set 1" to the workflow history list
  3. Set Field in Current Item (uses the OOTB action to assign "2" to the TextField column)
  4. Log "Set 2" to the workflow history list

This workflow runs perfectly, completing successfully with the workflow messages in order, and TextField==2.

However, if I move the last 2 actions to the top of the actions list, making the WF's single step then look like:

  1. Set Field in Current Item (uses the OOTB action to assign "2" to the TextField column)
  2. Log "Set 2" to the workflow history list
  3. Set Field to Value (uses my custom WFA to assign "1" to the TextField column)
  4. Log "Set 1" to the workflow history list

In this case, the workflow status is "Error Occurred", and even though TextField==1 (the second assignment) the only items in the workflow history are:

  1. Error updating a list item
  2. An error has occured in Set Field Test.

("Set Field Test" is the name of my SPD WF)

So, that's what the problem looks like: The WF works 100% if my custom WFA happens first, but fails every time (even though the field does get updated correctly) if my custom WFA happens second. I've repeated this test many times, including to perform the action reversal multiple times.

I might be doing something dumb in my custom WFA, so here it is (I've replaced my company's acronym with public agency - getting my tax dollars' worth) in its entirety:

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Reflection;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;

namespace NASA.workflowActivity {
public partial class TestSetFieldValueActivity : Activity {

    #region Dependency Properties

        public static DependencyProperty itemFieldProperty = DependencyProperty.Register("itemField", typeof(String), typeof(TestSetFieldValueActivity));

        public static DependencyProperty newValueProperty = DependencyProperty.Register("newValue", typeof(String), typeof(TestSetFieldValueActivity));

        public static DependencyProperty __ActivationPropertiesProperty = DependencyProperty.Register("__ActivationProperties", typeof(Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties), typeof(TestSetFieldValueActivity));

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Required)]
        [Browsable(true)]
        public String itemField {
            get { return base.GetValue(TestSetFieldValueActivity.itemFieldProperty).ToString(); }
            set { base.SetValue(TestSetFieldValueActivity.itemFieldProperty, value); }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Required)]
        [Browsable(true)]
        public String newValue {
            get { return base.GetValue(TestSetFieldValueActivity.newValueProperty).ToString(); }
            set { base.SetValue(TestSetFieldValueActivity.newValueProperty, value); }
        }

        [ValidationOption(ValidationOption.Required)]
        public Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties __ActivationProperties {
            get { return (Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties)base.GetValue(TestSetFieldValueActivity.__ActivationPropertiesProperty); }
            set { base.SetValue(TestSetFieldValueActivity.__ActivationPropertiesProperty, value); }
        }

    #endregion

    protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) {
        try {
            SPListItem listItem = this.__ActivationProperties.Item;
            SPField field = listItem.Fields[this.itemField];
            listItem[field.Id] = this.newValue;
            listItem.SystemUpdate();                
        } catch {
            return ActivityExecutionStatus.Faulting;
        }
        return ActivityExecutionStatus.Closed;
    }

}
}

And my .ACTIONS file (saved to C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\1033\Workflow ) contains this entry for this action:

<Action 
            Name="Set field in current item (Custom WFA)"
            ClassName="NASA.workflowActivity.TestSetFieldValueActivity"
            Assembly="NASA.workflowActivity, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f579ebeb24170bf5"
            AppliesTo="all"
            Category="NASA WFA: Test">
        <RuleDesigner Sentence="Set %1 to %2 (Custom WFA)">
            <FieldBind Id="1" Field="itemField" DesignerType="FieldNames" text="field" />
            <FieldBind Id="2" Field="newValue" DesignerType="Text" text="value" />
        </RuleDesigner>
        <Parameters>
            <Parameter Name="itemField" Type="System.String, mscorlib" Direction="In" />
            <Parameter Name="newValue" Type="System.String, mscorlib" Direction="In" />
            <Parameter Name="__ActivationProperties" Type="Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties, Microsoft.SharePoint" Direction="In" />
        </Parameters>
    </Action>

And finally, of course, my web.config contains an entry for my assembly.

This is a very simple action of course, but even it isn't working right in my SPD WF. I must be doing something wrong, but all the documentation I can find on creating a custom WFA makes this look correct. Can anyone see a problem in my code, or even try this out in your own environment?

回答1:

I have acually solved this problem in my open source project. Download the source code from http://spdactivities.codeplex.com/ and look at the source for one of the permission activities. The reason your code does not work is because the OOTB activities participate in a transaction and your custom activity does not. That is why your custom activity runs before all OOTB activities.

To participate in the workflow you need to implement IPendingWork and submit to WorkflowEnvironment.WorkBatch. HTH