Creating a Custom Pipeline Task
You will learn how to create a custom pipeline task. This is useful for when you would like to execute custom code as part of one of the Ucommerce pipelines (eg. Basket Pipeline, Checkout Pipeline)
In Ucommerce the majority of the functionality is executed as pipelines. You can read a full overview of our pipelines.
In this example, we'll create a pipeline task that will get executed as part of the Checkout pipeline. The purpose of this task is to notify the store administrator every time an order goes through the system. To achieve this we first need to:
- Create a Visual Studio project
- Create a class that implements
IPipelineTask<PurchaseOrder>
- Build and deploy the assemblies
- Configure the task in the configuration file
On to the Code
Below is the OrderCompletedTask
pipeline task which implements IPipelineTask
namespace UcommerceCodeSamples.Pipelines { public class OrderCompletedTask : IPipelineTask<PurchaseOrder> { private readonly IEmailService _emailService; private readonly ICatalogContext _catalogContext; private readonly IRepository<EmailProfile> _emailProfileRepository; public OrderCompletedTask(IEmailService emailService, ICatalogContext catalogContext, IRepository<EmailProfile> emailProfileRepository) { _emailService = emailService; _catalogContext = catalogContext; _emailProfileRepository = emailProfileRepository; }
The next step to achieve this is to implement the method Execute
which Ucommerce will be responsible for calling, whenever the Basket Pipeline is executed.
public PipelineExecutionResult Execute(PurchaseOrder subject) { CustomGlobalization localization = new CustomGlobalization(); localization.SetCulture(new CultureInfo(subject.CultureCode)); IDictionary<string,string> queryStringParams = new Dictionary<string, string>(); queryStringParams.Add("orderguid", subject.OrderGuid.ToString()); queryStringParams.Add("orderid", subject.OrderId.ToString(CultureInfo.InvariantCulture)); Guid emailProfileGuid = _catalogContext.CurrentCatalogGroup.EmailProfile; EmailProfile emailProfile = _emailProfileRepository.Select(x => x.Guid == emailProfileGuid).First(); _emailService.Send(localization, emailProfile, "Orders", new MailAddress("[email protected]"), queryStringParams); return PipelineExecutionResult.Success; }
Register the Task
To make Ucommerce use the task we've just created we need to register it as a component. Here's what the component registration looks like for our example:
<configuration> <components> <component id="ToCompletedOrder.SendOrderCompletedMail" service="Ucommerce.Pipelines.IPipelineTask`1[[Ucommerce.EntitiesV2.PurchaseOrder, Ucommerce]], Ucommerce" type="UCommerceCodeSamples.Pipelines.OrderCompletedTask, UCommerceCodeSamples" /> </components> </configuration>
Put this file in /Ucommerce/Apps/MyPipelineTask where it will be automatically picked up when the application starts up.
Interested in more details about components? Please see Register a Custom Component.
Once added it must be added to the pipeline you want it to be executed as part of.
Configure the Pipeline
Partial components enable you to configure just the changes to the list of tasks of a pipeline, rather than overriding the entire component or modifying the pipeline files directly as was the case in previous versions.
Here is an example of how to add the new task we created above, as the last task in the "ToCompletedOrder" pipeline.
<configuration> <components> <partial-component id="ToCompletedOrder"> <parameters> <tasks> <array> <value insert="last">${ToCompletedOrder.SendOrderCompletedEmail}</value> </array> </tasks> </parameters> </partial-component> </components> </configuration>
There are some important things to note:
- The id of the partial component must match the id of the pipeline component you wish to modify. In this case, it is the "ToCompletedOrder" pipeline component that is modified.
- The value inserted is using the id of the new custom component added in the previous examples, "ToCompletedOrder.SendOrderCompletedEmail".
- Most important is the attribute "insert" with the value "last". This instructs the configuration to add this task as the last task in the pipeline. In this example, it makes sense to have the send email task as the last one since we only want to perform it, if all other tasks have completed successfully.
The attributes supported are:
- "insert", with value either "first" or "last".
- "insert-before", with a value of the castle service override notation "${COMPONENTID}".
- "insert-after", with a value of the castle service override notation "${COMPONENTID}".
- "remove", with a value of the castle service override notation "${COMPONENTID}".
It is very important to note, that when using "insert-before" or "insert-after", the task is added after every occurrence of the service found in the pipeline. So be aware, that the task can be added more than once. Also note that "remove", will remove all instances of the matching tasks.
In the following example, a custom pipeline task called "MyCustomTask" is added to the basket pipeline after the task "Basket.CleanUp".
<configuration> <components> <partial-component id="Basket"> <parameters> <tasks> <array> <value insert-after="${Basket.CleanUp}">${MyCustomTask}</value> </array> </tasks> </parameters> </partial-component> </components> </configuration>
And an example of removing the "SendConfirmationEmail" task from the "Checkout" pipeline.
<configuration> <components> <partial-component id="Checkout"> <parameters> <tasks> <array> <value remove="${Checkout.SendConfirmationEmail}" /> </array> </tasks> </parameters> </partial-component> </components> </configuration>
The configuration file should be placed in Ucommerce/Apps/MyApp folder. It will automatically be picked up when the application starts up.
All there's left to do is build and deploy the assemblies into your Application's bin folder.
We've now extended the ToCompleted pipeline with a custom pipeline task.
Performance measurements of pipelines
Setting the Debug parameter to the value "true" enables the logging of performance measurements for the tasks of pipelines.
Using partial components configuration, enabling debug is very easy.
Simply add this partial component to the custom configuration file to enable debug for, in this example, the basket pipeline:
<configuration> <components> <partial-component id="Basket"> <parameters> <Debug>true</Debug> </parameters> </partial-component> </components> </configuration>
The end result is simply that the default pipeline implementation, if configured with debug enabled like above, is writing the execution time of each task into the log files.