Disclaimer: This website requires Please enable JavaScript in your browser settings for the best experience.

Dev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Pipelines

Overview of pipelines with code samples.

Pipelines are constructed from individual objects, called Pipes, that contain reusable business logic. Each pipe is responsible for completing a single, specific task. All of the pipes in a pipeline work together to complete a bigger, more complex task.

Pipes

All pipes must implement the IPipe<> interface, specifying the parameter and result object type according to the related pipeline.

IPipe\<> example

public interface IPipe<TIn, TOut> : IMultiInstanceDependency, IExtension
    {
        int Order { get; }
     
        TOut Execute(IUnitOfWork unitOfWork, TIn parameter, TOut result);
    }
  • Typically, a pipe operates on data within the result object or add data to the result object.

  • Each pipe must return the result object when it has completed its work. The result object determines whether the execution of the pipeline is continued.

  • Pipes are ordered within a pipeline and are executed in that order.

  • The order of a pipe within a pipeline is configured in code using a class property.

  • When adding a pipe to an existing pipeline, be aware of the order of existing pipes.

  • The first pipe in any pipeline have an order of 100. From there, the order of subsequent pipes are higher than that number. The pipes provided by Configured Commerce typically increment the order by 100 for each subsequent pipe. For example, the CreateGetCartLineResult pipeline has four pipes, whose order is displayed int he following screenshot.

  • Pipes in the same pipeline implement the IPipe interface, specifying the same object type for the parameter and result. The following example explains it further.

    IPipe interface

    // The GetInventory and CreateGetCartLineResult pipes execute in the same pipeline.
         public sealed class GetInventory : IPipe<CreateGetCartLineResultParameter, CreateGetCartLineResultResult>
         public sealed class CreateGetCartLineResult : IPipe<CreateGetCartLineResultParameter, CreateGetCartLineResultResult>
    // The CalculatePrice pipe executes in a separate pipeline from the two previous pipes.  
         public sealed class CalculatePrice : IPipe\<GetProductPricingParameter, GetProductPricingResult>

  • Pipes are ordered and executed in ascending order.

  • You cannot inherit from an existing pipe. If you need to modify the data created by a pipe, instead insert a new pipe after that pipe.

  • To insert a new pipe into a pipeline, create a class that implements IPipe with the appropriate parameter and result types. Then, indicate an order that is appropriate and different from any of the existing pipes. The following custom pipe is executed after the standard CreateGetCartLineResult pipe, which is in order 100 (as seen previously).
    Pipe ordering

    public class CustomPipe : IPipe<CreateGetCartLineResultParameter, CreateGetCartLineResultResult>
         {
             // Depending on the specific pipeline, this will place the pipe in a specific position.
             public int Order => 110;
          
             public CreateGetCartLineResultResult Execute(IUnitOfWork unitOfWork, CreateGetCartLineResultParameter parameter, CreateGetCartLineResultResult result)
             {
                 // ...
             }
         }
  • To override an existing pipe in a pipeline, name the custom pipe with the same pipe that should be replaced. The following custom pipe is executed instead of the standard CreateGetCartLineResult pipe. The order does not necessarily need to be the same as the standard pipe.

    Override pipe

    public class CreateGetCartLineResult : IPipe<CreateGetCartLineResultParameter, CreateGetCartLineResultResult>
         {
             // This pipe replaces the CreateGetCartLineResult pipe because the same order is configured.
             public int Order => 100;
          
             public CreateGetCartLineResultResult Execute(IUnitOfWork unitOfWork, CreateGetCartLineResultParameter parameter, CreateGetCartLineResultResult result)
             {
                 // ...
             }
         }
  • At any point during the lifetime of the pipeline, an individual pipe may stop the execution of a pipeline. To do this, the pipe must either assign an error code to the result object or set the exit flag on the result object.

    Stop the execution of a pipeline

    public class CustomPipe : IPipe<CreateGetCartLineResultParameter, CreateGetCartLineResultResult>
         {
             public CreateGetCartLineResultResult Execute(IUnitOfWork unitOfWork, CreateGetCartLineResultParameter parameter, CreateGetCartLineResultResult result)
             {
                 // To stop the execution of this pipeline, you can either return an error code in the result
                 result.ResultCode = ResultCode.Error;
          
                 // Or you can set this flag
                 result.ExitPipeline = true;
          
                 // The rest of the method will execute, but any pipes that follow will not
                 return new CreateGetCartLineResultResult();
             }
         }

Pipeline code sample

The following is an excerpt from a pipeline that retrieves product pricing. This pipeline contains only one pipe.

Retrieve Product Pricing Pipeline

public sealed class CalculatePrice : IPipe<GetProductPricingParameter, GetProductPricingResult>
 {
     private readonly IPricingServiceFactory pricingServiceFactory;
  
     private readonly Lazy<ITranslationLocalizer> translationLocalizer;
  
     public CalculatePrice(IPricingServiceFactory pricingServiceFactory, Lazy<ITranslationLocalizer> translationLocalizer)
     {
         this.pricingServiceFactory = pricingServiceFactory;
         this.translationLocalizer = translationLocalizer;
     }
  
     public int Order => 100;
  
     public GetProductPricingResult Execute(IUnitOfWork unitOfWork, GetProductPricingParameter parameter, GetProductPricingResult result)
     {
         foreach (var pricingServiceParameter in parameter.PricingServiceParameters)
         {
             var parameterWithOrderLine = pricingServiceParameter.Value as PricingServiceParameterWithOrderLine;
             var pricingService = this.pricingServiceFactory.GetPricingService(parameterWithOrderLine?.CustomerOrderId);
  
             var pricingServiceResult = pricingService.CalculatePrice(pricingServiceParameter.Value);
             var saveText = SiteContext.Current.LanguageDto != null
                 ? this.translationLocalizer.Value.TranslateLabel("Save")
                 : string.Empty;
             var productPriceDto = new ProductPriceDto(pricingServiceResult, saveText);
             result.ProductPriceDtos.Add(pricingServiceParameter.Key, productPriceDto);
         }
  
         return result;
     }
 }

Pipes order

Configured Commerce provides a Visual Studio extension that visually shows the order of the pipes within a pipeline.

  1. Right-click on the custom pipe.

  2. Select the Show Pipes Order menu item. A window displays that shows each the custom pipes in the order they execute.

Pipeline in code

To use a pipeline in code, simply have an instance injected into the class constructor like most other objects.

Using a Pipeline in Code

public class CustomHandler : HandlerBase<AddCartLineCollectionParameter, AddCartLineCollectionResult>
 {
     private readonly IPricingPipeline pricingPipeline;
  
     public RecalculateCart(IPricingPipeline pricingPipeline)
     {
         this.pricingPipeline = pricingPipeline;
     }
  
     public override AddCartLineCollectionResult Execute(IUnitOfWork unitOfWork, AddCartLineCollectionParameter parameter, AddCartLineCollectionResult result)
     {
         var getCartPricingResult = this.pricingPipeline.GetCartPricing(new GetCartPricingParameter(result.GetCartResult.Cart));
  
         // Do any processing here.
  
         return result;
     }
 }