How To Deal With Large Orders And Improve Checkout Performance

There are some scenarios were you need to handle 100 or more line items and performance becomes an issue. So in this post I hope to provide you with some ideas on how you can speed up the performance of the Checkout path.

Checkout Path

What is the checkout path? The checkout process starts from the moment the users enter the basket\cart page. Then, they navigates to shipping and billing page. This can either be one page or two. Next, they receives a confirmation page and finally, the users checks out and navigate to the receipt page.

Basket Display

This page shows the user what is in their basket. Usually the line item id, description, total line item cost, any discounts, total and subtotal. Bellow is an example:

Item ID Description Cost Quantity Discount Total
123-ABC My product description $10.00 1 $1.00 $9.00
Subtotal 9.00

You can also allow the user to enter promotion codes here if you site allows it.

The Basket pipeline file is executed in the page.

Basket Pipeline File

The Basket pipeline validates the line item product and removes any line items that does not validate again the Product Catalog System. Inventory is also checked. Pricing variables are initialized and used later on in the discount stage. Finally the subtotal is calculated.

Billing and Shipping Information

Some sites will have Billing and Shipping information on one page and some have it in two. These pages allows the user to select an address from their address book or enter a new one. The addresses can be used for shipping or shared as billing address. The billing section will also allow the user to enter a credit card.

This page executes the Basket and Total pipeline files.

Total Pipeline File

The Total pipeline computes the amount of an order and calculates Shipping, Handling, Tax, Order Total. This pipeline will also calculates any shipping discounts that need to be applied.

Confirmation Page

The confirmation page allows the user to validate their order before accepting the purchase. This page displays the line items and addresses for shipping and billing, payment methods and discounts applied.

This page executes Basket and Total pipeline files. 

Receipt Page

The receipt page is an exact duplicate page as the confirmation page that shows that the order has been purchased.

This page executes Basket, Total and Checkout pipeline files.

Checkout Pipeline File

The Checkout pipeline is responsible for redeeming promotion codes, decrement inventory, record Content Selection framework events, and finally the events are appended to the IIS log.

What about Add to Basket\Cart?

On some sites when the user adds an item to the basket they are redirected to the basket page like the Starter Site and some sites display a simple message that the item was added to the basket. The sites that don't redirect the user need to only validate the product against the Product Catalog System. To do this you only need to execute the Product pipeline component.

Product Pipeline File

Product pipeline validates that the product is in synch with the Product Catalog System.

Why are we executing the pipelines over and over?

Because the user can wait indefinite time between pages and prices, products or discounts could be invalid we need to execute the pipelines to ensure the accuracy of the basket before converting it to purchase order.

What happens when I execute a pipeline?

Commerce Server basket has several entities such as OrderForm, LineItems, Addresses, Shipments to name a few. These objects are based on .NET. The Commerce Server Processing Pipeline is COM. When a pipeline is executed the managed objects in the basket need to be converted into a dictionary. Commerce Server does this for you before executing the pipeline file. When the execution of the pipeline is completed, the process is reversed. If you are interested in a detailed explanation of pipelines then I suggest you read the following posts.

How to improve performance?

  1. Do not use scriptor pipeline Components. Scriptor Component is good for quick and dirty proof of concept.
  2. When creating custom pipeline Components then enable pooling for your pipelines.
  3. Follow the basics of .NET performance coding techniques. Here is a couple of reads for you Improving ASP.NET Performance, Improving Interop Performance and Improving Managed Code Performance.
  4. Don't create Commerce Contexts inside your custom pipelines pass them as pipeline Context values.
  5. When adding items to the basket don't redirect the user to the basket page. Imagine if 25 percent of your users add more than one item to their basket, now you are executing the basket 25 more times then necessary.
  6. Don't iterate the lineitems object then get a Commerce product object, the lineitem is filled with all it's properties in the Product Info of basket pipeline stage, try to use what's there.
  7. Remove unwanted pipeline components, for example if you are not using the Inventory System then remove the CheckInventory and Update Inventory.
  8. If you don't have or not using the data warehouse then you can remove the CSFRecordEvent and CSFIISAppendToLog.
  9. Create one pipeline component for each page, this will reduce the transformation of .NET object to COM and back. For example you would create a BillingShipping.pcf that has the combined basket and Total files and the same is true for the receipt page.
  10. Don't keep to many weakly types because most of your time will be spent in serialization when they are stored in the marshalled data field.
  11. Add business logic that if the lineitem collection is more than 50 or whatever your business requirements are then execute them offline. This would mean that you have to create an application that runs large orders for you.
  12. If your business can't support this scenario then keep one server available for large order scenario. When you detect large orders then redirect the checkout process to another server that does nothing but handle large orders.
  13. If your business allows then don't execute the basket pipeline stages during the shipping and billing only the Total as you will catch any issues when the users tries to complete the purchase.

If you have additional ideas please post a comment for others.

Comments (4)

  1. Simon Clark says:

    Hi Max

    On point 4, you mention not creating commerce contexts inside the pipeline components. Do you mean we should use CatalogContext context = CommerceContext.Current.CatalogSystem; or do we use some other context object specifically for pipelines?

    If so, what is this other object for getting a handle to the context so we can access CS2007 product and order details?

    Thank you


  2. Simon Clark says:

    Hi Max

    On point 10, you mention weak types. What weak types are you refering to? We are currently getting all information from the pdispOrder parameter that is passed into the Execute method of the component.


    public int Execute(object pdispOrder, object pdispContext, int lFlags)

    we then get the order like this:

    order = (IDictionary)pdispOrder;

    Is this the best way of doing this? Or are you refering to another way of passing values to the Components?

  3. MSDN Archive says:

    On point number four I mean don’t do the following inside of the component:

    CatalogSiteAgent siteAgent = new CatalogSiteAgent();

    siteAgent.SiteName = “StarterSite”;

    CatalogContext context = CatalogContext.Create(siteAgent);

    So how would you pass the catalog context? I would recommend doing the following:

    Befor running the pipeline component you need to pass the context.

    Basket basket = CommerceContext.Current.OrderSystem.GetBasket(userID);

    PipelineInfo pipeinfo = new PipelineInfo(“Basket”);

    pipeinfo[“CatalogContext”] = CommerceContext.Current.CatalogSystem;


    Now inside your pipeline component you need to get the context:

    public class Class1 : IPipelineComponent


       public void EnableDesign(int fEnable){}

      public int Execute(object pdispOrder, object pdispContext, int lFlags)


           IDictionary Context = (IDictionary)pdispContext;

           CatalogContext my CatalogContext = (CatalogContext)Context[“CatalogContext “];

          return 1;



  4. MSDN Archive says:

    On point ten I mean that don’t do the following unless you have too:

               LineItem item = new LineItem("Adventure Works Catalog", "AW099-15", null, 1);

               item["x"] = "x";

               item["x1"] = "x1";

               item["x2"] = "x2";

               item["x3"] = "x3";

               item["x4"] = "x4";

               item["x5"] = "x5";

               item["x6"] = "x6";

               item["x7"] = "x7";

               item["x8"] = "x8";

               item["x9"] = "x9";

               item["x10"] = "x10";

    The same is ture for OrderForm.

    What happens is that when the basket.SaveAsOrder() is called the data is saved under MarshalledData filed in the lineitem table.


Skip to main content