Sometimes it is required to check the previous value in a workflow triggered when record is updated.
The out of the box workflow create user interface only provide access to current value of the record which is the value after modification.
We could write one custom workflow activity to retrieve that value from IExecutionContext, which can be accessed from IWorkflowContext within custom workflow activity.
protected override void Execute(CodeActivityContext executionContext)
{
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
Entity preImageEntity = context.PreEntityImages.Values.FirstOrDefault();
}
When use InOutArgument<EntityReference > in custom workflow activity, we need to specify the entity name which made it difficult to reuse, instead we could accept the attribute name of the lookup field and output entity name and record id for that lookup field. We can use entity name and record id in other workflow activity to perform generic tasks.
Here is a sample code to retrieve record id and entity name from custom workflow activity
public sealed class GetRecordIdEntityName : CodeActivity
{
[Input("Attribute Name for Related Record")]
public InArgument<String> AttributeName { get; set; }
[Output("Primary Entity Name")]
public OutArgument<String> PrimaryEntityName { get; set; }
[Output("Primary Record Id")]
public OutArgument<String> PrimaryRecordId { get; set; }
[Output("Related Entity Name")]
public OutArgument<String> RelatedEntityName { get; set; }
[Output("Pre Related Record Id")]
public OutArgument<String> PreRelatedRecordId { get; set; }
[Output("Post Related Record Id")]
public OutArgument<String> PostRelatedRecordId { get; set; }
/// <summary>
/// Executes the workflow activity.
/// </summary>
/// <param name="executionContext">The execution context.</param>
protected override void Execute(CodeActivityContext executionContext)
{
// Create the tracing service
ITracingService tracingService = executionContext.GetExtension<ITracingService>();
if (tracingService == null)
{
throw new InvalidPluginExecutionException("Failed to retrieve tracing service.");
}
tracingService.Trace("Entered GetRecordId.Execute(), Activity Instance Id: {0}, Workflow Instance Id: {1}",
executionContext.ActivityInstanceId,
executionContext.WorkflowInstanceId);
// Create the context
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
if (context == null)
{
throw new InvalidPluginExecutionException("Failed to retrieve workflow context.");
}
tracingService.Trace("GetRecordId.Execute(), Correlation Id: {0}, Initiating User: {1}",
context.CorrelationId,
context.InitiatingUserId);
IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
try
{
// TODO: Implement your custom Workflow business logic.
ExecuteCore(executionContext, context, service);
}
catch (FaultException<OrganizationServiceFault> e)
{
tracingService.Trace("Exception: {0}", e.ToString());
// Handle the exception.
throw;
}
tracingService.Trace("Exiting GetRecordId.Execute(), Correlation Id: {0}", context.CorrelationId);
}
private void ExecuteCore(CodeActivityContext executionContext, IWorkflowContext context, IOrganizationService service)
{
this.PrimaryRecordId.Set(executionContext, context.PrimaryEntityId.ToString());
this.PrimaryEntityName.Set(executionContext, context.PrimaryEntityName.ToLowerInvariant());
string attributeName = this.AttributeName.Get(executionContext);
this.RelatedEntityName.Set(executionContext, null);
if (!string.IsNullOrWhiteSpace(attributeName))
{
Entity preImageEntity = context.PreEntityImages.Values.FirstOrDefault();
if (preImageEntity != null && preImageEntity.Contains(attributeName) && preImageEntity[attributeName] is EntityReference)
{
EntityReference entityRef = preImageEntity.GetAttributeValue<EntityReference>(attributeName);
this.RelatedEntityName.Set(executionContext, entityRef.LogicalName.ToLowerInvariant());
this.PreRelatedRecordId.Set(executionContext, entityRef.Id.ToString());
}
else
{
this.PreRelatedRecordId.Set(executionContext, null);
}
Entity postImageEntity = context.PostEntityImages.Values.FirstOrDefault();
if (postImageEntity != null && postImageEntity.Contains(attributeName) && postImageEntity[attributeName] is EntityReference)
{
EntityReference entityRef = postImageEntity.GetAttributeValue<EntityReference>(attributeName);
this.RelatedEntityName.Set(executionContext, entityRef.LogicalName.ToLowerInvariant());
this.PostRelatedRecordId.Set(executionContext, entityRef.Id.ToString());
}
else
{
this.PostRelatedRecordId.Set(executionContext, null);
}
}
else
{
this.PreRelatedRecordId.Set(executionContext, null);
this.PostRelatedRecordId.Set(executionContext, null);
}
}
}