11

I am writing custom activity for sharepoint workflow and I don't know how I can use current workflow item, SPWeb or SPSite.

I see http://blogs.microsoft.co.il/blogs/davidbi/archive/2008/07/21/How-to-get-the-context-item-in-workflow-activity-sharepoint.aspx but xml routines of this solution is too bad for me.

Perhaps there is another code-only solution to get context item in Workflow activity?

user656
  • 347
  • 1
  • 4
  • 17
  • I did everything as described here, and yet my context is always null too. I'm coding a custom SPDesigner Activity based on SequenceActivity. Even more, when I try editing the WF in Sharepoint Designer I can't save it because of an error. –  Feb 16 '11 at 12:13

6 Answers6

19

The answer to this is a couple steps:

  1. Add the properties to your Custom Activity .cs
  2. Link the properties in your .actions file (so SPD knows how to map to your properties)
  3. Use the properties in your code

STEP 1: Here is the code for the properties (my class is named GetEmails which you will need to rename to be your class):

public static DependencyProperty __ContextProperty = System.Workflow.ComponentModel.DependencyProperty.Register("__Context", typeof(WorkflowContext), typeof(GetEmails));

[Description("The site context")]
[Category("User")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public WorkflowContext __Context
{
    get
    {
        return ((WorkflowContext)(base.GetValue(GetEmails.__ContextProperty)));
    }
    set
    {
        base.SetValue(GetEmails.__ContextProperty, value);
    }
}

public static DependencyProperty __ListIdProperty = System.Workflow.ComponentModel.DependencyProperty.Register("__ListId", typeof(string), typeof(GetEmails));

[ValidationOption(ValidationOption.Required)]
public string __ListId
{
    get
    {
        return ((string)(base.GetValue(GetEmails.__ListIdProperty)));
    }
    set
    {
        base.SetValue(GetEmails.__ListIdProperty, value);
    }
}

public static DependencyProperty __ListItemProperty = System.Workflow.ComponentModel.DependencyProperty.Register("__ListItem", typeof(int), typeof(GetEmails));

[ValidationOption(ValidationOption.Required)]
public int __ListItem
{
    get
    {
        return ((int)(base.GetValue(GetEmails.__ListItemProperty)));
    }
    set
    {
        base.SetValue(GetEmails.__ListItemProperty, value);
    }
}

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

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

STEP 2: Then in your .actions file add to your block the mappings for those properties (note the entries for __ListID, __ListItem, __Context, and __ActivationProperties):

<Action Name="[DESCRIPTION OF YOUR ACTION]"
  ClassName="[Your.Namespace.Goes.Here].GetEmails"
  Assembly="[yourDLLName], Version=1.0.0.0, Culture=neutral, PublicKeyToken=0bfc6fa4c4aa913b"
  AppliesTo="all"
  Category="[Your Category Goes Here]">
  <RuleDesigner Sentence="[blah blah blah]">
    <FieldBind Field="PeopleFieldName" Text="people field" Id="1"/>
    <FieldBind Field="Output" Text="emailAddress" Id="2" DesignerType="parameterNames" />
  </RuleDesigner>
  <Parameters>
    <Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext" Direction="In" />
    <Parameter Name="__ListId" Type="System.String, mscorlib" Direction="In" />
    <Parameter Name="__ListItem" Type="System.Int32, mscorlib" Direction="In" />
    <Parameter Name="PeopleFieldName" Type="System.String, mscorlib" Direction="In" />
    <Parameter Name="Output" Type="System.String, mscorlib" Direction="Out" />
    <Parameter Name="__ActivationProperties" Type="Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties, Microsoft.SharePoint" Direction="Out" />
  </Parameters>
</Action>

STEP 3: Here is an example execute function:

protected override ActivityExecutionStatus Execute(ActivityExecutionContext provider)
{
    Output = string.Empty;

    try
    {
        SPWeb web = __Context.Web;
        // get all of the information we currently have about the item
        // that this workflow is running on
        Guid listGuid = new Guid(__ListId);
        SPList myList = web.Lists[listGuid];
        SPListItem myItem = myList.GetItemById(__ListItem);

        //...
    }
    catch (Exception e)
    {
        //...
    }

    return ActivityExecutionStatus.Closed;
}
Kit Menke
  • 7,046
  • 1
  • 32
  • 54
3

I'm not sure if this is a change in the 2010 API but the __Context property provides all the necessary pieces, including the list and item. The example below includes @davek's suggestion for discarding the security context:

            var contextWeb = __Context.Web;
            var site = new SPSite(contextWeb.Url);
            var web = site.OpenWeb();

            var list = web.Lists[new Guid(__Context.ListId)];
            var item = list.GetItemById( __Context.ItemId);
David Clarke
  • 12,888
  • 9
  • 86
  • 116
2

Kit Menke's answer is very comprehensive and covers just about all you need: I would only add the following...

If you do this:

SPWeb tmpweb = __Context.Web;
SPSite site = new SPSite(tmpweb.Url);
SPWeb web = site.OpenWeb();

instead of this:

SPWeb web = __Context.Web;
...

then you are free of the security context passed through to the workflow by the person who triggered it.

davek
  • 22,499
  • 9
  • 75
  • 95
1

Take a look at the SPWorkflowActivationProperties.Item Property

Gets the list item on which the workflow instance is running.

user4531
  • 2,525
  • 7
  • 30
  • 38
  • 1
    Hm.. I implement my own activity from SequenceActivity base class. Where I can find SPWorkflowActivationProperties instance in this case? – user656 Aug 07 '09 at 10:30
1

I try this code and runs as well bat the contex objet always is null. some one know why?

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
    {


        //return base.Execute(executionContext);
        int IdRetorno = -1;



        try {
            SPSecurity.RunWithElevatedPrivileges(delegate
            {
                LogExceptionToWorkflowHistory("Inicio:", executionContext, WorkflowInstanceId);
                using (SPSite sitio = new SPSite(this.__Context.Site.ID))
                {

                    using (SPWeb web = sitio.AllWebs[this.__Context.Site.ID])
                    {


                        SPList sourceList = web.Lists[new Guid(ListId)];
                        LogExceptionToWorkflowHistory(ListId, executionContext, WorkflowInstanceId);
                        SPList destinoList = web.Lists[new Guid(SourceListId)];
                        LogExceptionToWorkflowHistory(SourceListId, executionContext, WorkflowInstanceId);
                        SPListItem sourceItem = sourceList.Items.GetItemById(ListItem);
                        LogExceptionToWorkflowHistory(ListItem.ToString(), executionContext, WorkflowInstanceId);

                        SPListItem destinoItem = destinoList.Items.Add();
                        CopyFieldValues(sourceItem, destinoItem);
                        destinoItem.SystemUpdate();

                        sourceItem.Delete();
                        IdRetorno = destinoItem.ID;
                    }
                }

            });

        }
        catch (Exception ex) {
            if (!System.Diagnostics.EventLog.SourceExists("MyApp1"))
                System.Diagnostics.EventLog.CreateEventSource(
                   "MyApp1", "Application");

            EventLog EventLog1 = new EventLog();
            EventLog1.Source = "MyApp1";
            EventLog1.WriteEntry(ex.Message,EventLogEntryType.FailureAudit);

            LogExceptionToWorkflowHistory(ex.Message, executionContext, WorkflowInstanceId);
        }


        OutListItemID = IdRetorno;




        return base.Execute(executionContext);

    }

thanks

Pablo
  • 11
  • 1
  • My guess is because it is wrapped within the RunWithElevatedPrivileges block. I think you'd have to pass the site id some other way? – Kit Menke Dec 15 '10 at 00:12
1

I don't know if this is too easy, but I used:

objCurrentItem = workflowProperties.Item

to get the item within the workflow (a list) and then to alter the items in the list

GMD
  • 698
  • 5
  • 12
JoshNair
  • 11
  • 1