Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more
Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more
This topic describes the customization of activity flows. To replace or customize an activity flow:
Classes in this topic are available in the following namespaces:
Configure the activity flows in a .CS file (the config file \Configs\ecf.workflow.config is no longer needed).
An activity flow should inherit from the ActivityFlow class, and you can decorate it with an ActivityFlowConfiguration attribute.
[ActivityFlowConfiguration(Name = “Example”)]
public class ExampleActivityFlow : ActivityFlow
Each activity flow should have a unique name. If the Name parameter is not provided, the engine gets the ActivityFlow class name. In this example, Name is ExampleActivityFlow. The activity flow name will be used to look up and execute.
Example: ExecutionManager.ExecuteActivityFlow(workflowName, parameters)
An activity flow should implement a Configure method to declare which activities are executed, and how they are executed. You can configure an activity flow to override another flow of the same name and mode by setting a higher priority. The default priority is zero (0). For example, you configure two flows with the same name and all in beta mode:
[ActivityFlowConfiguration(Name = “Example”)]
public class BetaExampleActivityFlow : ActivityFlow
[ActivityFlowConfiguration(Name = “Example”, Priority = 1)]
public class AlphaExampleActivityFlow : ActivityFlow
When the activity flow “Example” is called in beta mode, it creates an instance of AlphaExampleActivityFlow class, not BetaExampleActivityFlow. This means that only the AlphaExampleActivityFlow is registered for the “Example” activity flow.
Note: You can register a workflow without the ActivityFlowConfiguration attribute. If a workflow is inherited from the ActivityFlow class and not decorated by the attribute, it is still registered with same name as the name of class.
The following example creates a new workflow activity, then uses it in a new workflow. It uses this workflow to replace the shipped CartCheckout workflow. The new activity sends an automated email to store customers after an order completion. This example illustrates how to update and customize a flow.
Note: Use the activity OrderGroup object reference to retrieve the information about the order to be put in the email. To generate the formatted copy of the email body text with the order information, use the Mediachase.Commerce.Engine.Template.TemplateService. See sending Order Notifications for information about setting up and using the template service.
Add the activity created above (along with other activities contained in the Mediachase.Commerce.Workflow.dll) to a new activity flow. Use this activity flow to replace the CartCheckoutActivityFlow (Mediachase.Commerce.Workflow.CartCheckoutActivityFlow).
Example: starting code for the SendNotification activity.
using Mediachase.Commerce.Engine;
using Mediachase.Commerce.Orders;
using Mediachase.Commerce.WorkflowCompatibility;
using System;
namespace CustomActivity
{
public partial class SendNotification : Activity
{
///
/// Gets or sets the order group.
///
///The order group.
[ActivityFlowContextProperty]
public OrderGroup OrderGroup { get; set; }
///
/// Called by the workflow runtime to execute an activity.
///
///The to associate with this and execution.
///
/// The of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
///
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
try
{
// Validate the properties at runtime
this.ValidateRuntime();
//Send notification
this.SendEmailNotification();
// Retun the closed status indicating that this activity is complete.
return ActivityExecutionStatus.Closed;
}
catch
{
// An unhandled exception occured. Throw it back to the WorkflowRuntime.
throw;
}
}
///
/// Calculates the sale taxes.
///
private void SendEmailNotification()
{
//provide implementation here
}
///
/// Validates the runtime.
///
///
private bool ValidateRuntime()
{
// Create a new collection for storing the validation errors
ValidationErrorCollection validationErrors = new ValidationErrorCollection();
// Validate the Order Properties
this.ValidateOrderProperties(validationErrors);
// Raise an exception if we have ValidationErrors
if (validationErrors.HasErrors)
{
string validationErrorsMessage = String.Empty;
foreach (ValidationError error in validationErrors)
{
validationErrorsMessage +=
string.Format("Validation Error: Number {0} - '{1}' \n",
error.ErrorNumber, error.ErrorText);
}
// Throw a new exception with the validation errors.
throw new WorkflowValidationFailedException(validationErrorsMessage, validationErrors);
}
// If we made it this far, then the data must be valid.
return true;
}
private void ValidateOrderProperties(ValidationErrorCollection validationErrors)
{
// Validate the To property
if (this.OrderGroup == null)
{
ValidationError validationError = ValidationError.GetNotSetValidationError("OrderGroup");
validationErrors.Add(validationError);
}
}
}
}
Example: CustomCartCheckout.cs.
using Mediachase.Commerce.Engine;
using Mediachase.Commerce.Workflow.Activities;
using Mediachase.Commerce.Workflow.Activities.Cart;
namespace CustomActivity
{
[ActivityFlowConfiguration(Name = "CartCheckout")]
public class CustomCartCheckout : ActivityFlow
{
public override ActivityFlowRunner Configure(ActivityFlowRunner runner)
{
return runner.If(() => ShouldProcessPayment())
.Do<ProcessPaymentActivity>()
.EndIf()
.Do<CalculateTotalsActivity>()
.Do<AdjustInventoryActivity>()
.Do<RecordPromotionUsageActivity>()
.Do<SendNotification>();
}
}
}
Last updated: Oct 12, 2015