Pages

Tuesday, April 21, 2009

Making a manual Workflow understand who ran it.

So, I ran into a situation that I've seen a few people butt up against: Workflows have no register that connects to the executing user. By and large, all automatic workflows execute within the context of the User that established the Workflow. However, for those "on demand" workflows, the context changes to the user who has selected to run the workflow. This is awesome because there is an accounting of who has performed a certain function. What's unawesome about this, is that the Workflow's internal workings can't access this data natively. Huge bummer.

So, I short-circuited it with a very simple custom Workflow activity that returns a systemuser reference of whomever executed the workflow:

using System; 
using System.Collections; 
using System.Workflow.Activities; 
using System.Workflow.ComponentModel; 
using Microsoft.Crm.Sdk; 
using Microsoft.Crm.Sdk.Query; 
using Microsoft.Crm.SdkTypeProxy; 
using Microsoft.Crm.Workflow; 

namespace CrmWorkflows
{ 
  /// <summary> 
  /// Defines the workflow action, and places it in a container directory 
  /// </summary> 
  [CrmWorkflowActivity("Who Am I", "General Utilities")] 
  
  public class WhoAmI : Activity 
  {   
    #region Define Output systemUserLookup 
    
    /// <summary> 
    /// Workflow dependency property for systemUserLookup 
    /// </summary> 
    public static DependencyProperty systemUserLookupProperty = DependencyProperty.Register("systemUserLookup", typeof(Lookup), typeof(WhoAmI)); 
    
    /// <summary> 
    /// CRM Output definition for systemUserLookup 
    /// </summary> 
    [CrmOutput("User")] [CrmReferenceTarget("systemuser")] 
    public Lookup systemUserLookup 
    { 
      get 
      { 
        return (Lookup)base.GetValue(systemUserLookupProperty); 
      } 
    
      set 
      { 
        base.SetValue(systemUserLookupProperty, value); 
      } 
    } 
    
    #endregion 
    
    #region Activity Members 
    
    /// <summary> 
    /// Overridden Execute() function to provide functionality to the workflow. 
    /// </summary> 
    /// <param name="executionContext">Execution context of the Workflow</param> 
    /// <returns></returns> 
    protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) 
    { 
      IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService)); 
      IWorkflowContext context = contextService.Context; 
      
      systemUserLookup = new Lookup(EntityName.systemuser.ToString(), context.UserId); 
      
      return ActivityExecutionStatus.Closed; 
    } 
    
    #endregion 
  } 
}