2

I am in the process of upgrading our custom solutions to Sharepoint 2010. I wanted to utilize the WorkflowCompleted event handler but I don't seem to be able to get the relevant SPListItem from the event properties.

I tried using SPWorkflowEventProperties.ActivationProperties but this always returns null (even in the WorkflowStarted event handler).

How do I get the context from workflow event handlers (SPListItem, SPWeb, SPSite etc)?

hrossi
  • 55
  • 1
  • 2
  • 7
  • I'm posting this as a comment because I can't verify.. but would it be the same as in 2007? See http://stackoverflow.com/questions/1243736/how-to-get-the-context-item-in-workflow-activity-sharepoint/1257293#1257293 – Kit Menke May 03 '11 at 21:18

3 Answers3

2

I've found the same thing. SPWorkflowEventProperties is practically useless since just about everything is null. It doesn't tell status (Approved, Rejected, etc). And, most importantly, it doesn't (directly) tell what item was completed. Hopefully this will be addressed in future versions. In the meantime, I used the following:

public override void WorkflowCompleted(SPWorkflowEventProperties properties)
{
   using (SPSite site = new SPSite(properties.WebUrl))
   {
       using (SPWeb web = site.OpenWeb())
       {
           SPListItem task = GetApprovedTask(properties, web);
           SPListItem item = GetApprovedItem(web, task);
           if (null != item)
           {
               // TODO : process approved item
           }
       }
   }
}

private SPListItem GetApprovedItem(SPWeb web, SPListItem task)
{
   SPListItem item = null;
   if (null != task)
   {
       SPList list = web.Lists[new Guid(task[SPBuiltInFieldId.WorkflowListId].ToString())];
       item = list.GetItemById((int)task[SPBuiltInFieldId.WorkflowItemId]);
   }
   return item;
}

private SPListItem GetApprovedTask(SPWorkflowEventProperties properties, SPWeb web)
{
   SPListItem item = null;
   string caml = @"<Where><And><And><And><Eq><FieldRef Name='WorkflowOutcome' /><Value Type='Text'>Approved</Value></Eq><Eq><FieldRef Name='WorkflowInstanceID' /><Value Type='Guid'>{0}</Value></Eq></And><IsNotNull><FieldRef Name='WorkflowListId' /></IsNotNull></And><IsNotNull><FieldRef Name='WorkflowItemId' /></IsNotNull></And></Where>";
   SPQuery query = new SPQuery();
   query.Query = string.Format(caml, properties.InstanceId);
   query.RowLimit = 1;
   SPList list = web.Lists["Tasks"];
   SPListItemCollection items = list.GetItems(query);
   if (items.Count > 0)
   {
       item = items[0];
   }
   return item;
}
Rich Bennema
  • 10,295
  • 4
  • 37
  • 58
  • Thank you Rich. In SP 2007, I've been using ItemUpdated and fetch the workflow context from within that event but I was hoping that the new events would enable a more elegant solution. Frustrating that the workflowProperties are almost unusable but your solution is a step in the right direction. As you said, hopefully Microsoft will solve this in future updates. Unfortunately, I don't have enough rep to +1 your answer. – hrossi May 04 '11 at 20:57
  • By the way @Rich, there's a small error in your code: you'll want to use `using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl))` on line 5 to fetch the correct SPWeb. If you don't you'll always get a reference to the root web of the site collection. – hrossi May 04 '11 at 21:08
1

You can use the InstanceId property to retrieve the SPListItem from the workflow task list as shown in this post

http://blog.symprogress.com/2011/09/sp-2010-get-workflow-status-workflowcompleted-event/

Budi Darma
  • 11
  • 1
0

If you can be more generous with details I can be more specific with answer.

But this is generally what you need to do:

  1. Set context specific properties

    public static DependencyProperty _ContextProperty = System.Workflow.ComponentModel.DependencyProperty.Register("_Context", typeof(WorkflowContext), typeof(MyCustomActivity));

[Description("Site Context")] [Category("User")] [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]

public WorkflowContext __Context
{
    get
    {
        return ((WorkflowContext)(base.GetValue(MyCustomActivity.__ContextProperty)));
    }

    set
    {
        base.SetValue(MyCustomActivity.__ContextProperty, value);
    }
}

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

[ValidationOption(ValidationOption.Required)]

public string __ListId
{
    get
    {
        return ((string)(base.GetValue(MyCustomActivity.__ListIdProperty)));
    }

    set
    {
        base.SetValue(MyCustomActivity.__ListIdProperty, value);
    }
}

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

[ValidationOption(ValidationOption.Required)]

public int __ListItem
{
    get
    {
        return ((int)(base.GetValue(MyCustomActivity.__ListItemProperty)));
    }

    set
    {
        base.SetValue(MyCustomActivity.__ListItemProperty, value);
    }
}

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

[ValidationOption(ValidationOption.Required)]

public Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties __ActivationProperties
{
    get
    {
        return (Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties)base.GetValue(MyCustomActivity.__ActivationPropertiesProperty);
    }

    set
    {
        base.SetValue(MyCustomActivity.__ActivationPropertiesProperty, value);
    }
}
  1. You will get context in __Context and everything else from __Context like this:

    protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { // Raise Invoke Event to execute custom code in the workflow. this.RaiseEvent(MyCustomActivity.InvokeEvent, this, EventArgs.Empty);

    SPWeb _cxtWeb = null;
    String _strLinfo = "Dll;";
    String _strTo = String.Empty;
    
    // Set Context
    try
    {
        SPSecurity.RunWithElevatedPrivileges(delegate()
        {
            using (_cxtWeb = __Context.Web)
            {
                //_cxtWeb = __Context.Web;
                Guid _cListId = new Guid(__ListId);
                SPList _cSPList = _cxtWeb.Lists[_cListId]; // TimeLog
                SPListItem _cListItem = _cSPList.GetItemById(__ListItem);
                SMTPSERVER = _cxtWeb.Site.WebApplication
                                            .OutboundMailServiceInstance.Server.Address;
            }
        });
    }
    catch { /**/ }
    

    }

ukhardy
  • 2,084
  • 1
  • 13
  • 12