Area: Optimizely Commerce
Applies to versions: 9

Commerce 9 - upgrading and migration

Recommended reading 

How it works

After upgrading the code base and database (by executing "update-epidatabase cmdlet" like before), you need to migrate existing data to the new version system. To reduce possible website downtime due to migration, the process is split into these main steps:

  • Migration of "active" and most used content versions, via the migration procedure.
  • Migration of previously-published content versions using a scheduled job.

After the migration, database size will increase since version data is now stored in the Commerce database instead of the CMS database. Furthermore, data is stored in tables with many rows instead of tables with many columns, which significantly improves performance. Information for a version of a property in one language is now stored in one row in the database. The size of the database depends on the number of versions, product properties, and entries. You can also shrink the database to reduce the size, see Microsoft documentation.

To get the best performance when migrating data, as well as to prevent a timeout error when managing a large number of records, batch processing is used. The default number of records to be processed in a batch is 5000. If you experience a timeout issue when migrating, or if you want to increase this number, you can add the following to the AppSetting:

<add key="ecf:DraftMigrationBatchSize" value="10000" />

Only enabled catalogs will be migrated. Drafts created within a disabled catalog are not migrated, and are removed when migration is complete.

Migration of most used versions

This step migrates of the most "active" and used content versions:

  • Published
  • Ready to publish (check in)
  • Delayed publish (check out)
  • Rejected

After this migration step is done, visitors can visit the site and place orders, content can be edited, and versions set for delayed publishing can be published as scheduled.

If the DisableVersionSync AppSetting is enabled, no versions are migrated in this step.

<add key="DisableVersionSync" value="true" />

Migration of versions for project items

First, all content versions associated with project items are migrated, then the “Migrate most used versions” is executed. If a version was already migrated, the “Migrate most used versions” step ignores it.

If the parameter DisableVersionSync is enabled (true), no versions are migrated, and the linked item disappears from the project items list after migration. If a project item is in a draft version, it also disappears from the project items list if DisableVersionSync is enabled.

Migration of inactive content without DDS versions

This step is used for "inactive" content that has versions in memory, but has not been persisted in DDS (Dynamic Data Store), and therefore would be ignored in the previous migration step. This step checks for a block (with a configurable batch size) of inactive catalogs with at least one available language, inactive nodes and inactive entries. If an item does not have a version, a draft is created. This step also updates project items associated with this content. The procedure is repeated until draft versions are created (in the ecfVersion table) for all inactive content.

If the parameter DisableVersionSync is enabled (true), no versions are migrated, and the linked item disappears from the project items list after migration.

Migration of previous published versions

Previously published content versions usually take up most of the storage space, so migrating this content may be slow. In most cases, the website works properly without these content versions. So, you can complete the migration of this content later, in a separate, optional step using a scheduled job, which can be run at a time of reduced site traffic.

If the DisableVersionSync AppSetting is enabled, no versions are migrated, and the Draft store is removed immediately.

When you have your site up and running, go to the CMS Admin view and activate and schedule the Draft store migration job.

In AppSetting, a setting lets you configure a time span within which the job should run. By default this is one hour. If the migration job takes more than one hour to complete, the job commits all changes, stops, and resumes at the next scheduled occasion.

<add key="ecf:DraftMigrationTimeSpan" value="1:0:0" />

When all content versions are migrated, the scheduled job setting is removed.

Removal of stored procedures

During migration, some temporarily stored procedures and types are also removed from the CMS database. If the migration procedure does not have database permissions to remove these, you may need to do so manually:

  • DraftStore_DeleteByID stored procedure
  • tblProjectItem_MigrateWorkID stored procedure
  • WorkIDMappingTable type

After completion of the data migration procedure, some unused Commerce metadata plus procedures for catalogs are also removed:

  • All procedures starting with “mdpsp_avto_CatalogNodeEx_ ...”
  • All procedure starting with “mdpsp_avto_CatalogEntryEx_...” 

Migration of Workflow and Activity projects

After upgrading to version 9, you need to update and migrate existing workflows and activity projects to remove obsolete workflows and use the new engine.

Do the following:

  • Remove Mediachase.Commerce.WorkflowSystem.Workflow.ActivitiesSystem.Workflow.ComponentModel and System.Workflow.Runtime referenced assemblies from the Workflow and Activity projects.
  • Open the Workflow and Activityproject files, scroll down to the bottom, and delete the following tag: <Import Project="$(MSBuildToolsPath)\Workflow.Targets" />
  • Check the AssemblyInfo.cs file and remove the line “using System.Workflow.ComponentModel.Serialization;” if it exists.

To use the new DLL after migrating, you may also need to copy its dependencies to objects which do not exist in the site. For example, your migrated workflow project may still use log4net, but your site was now upgraded to Commerce 9 where log4net is not used. This means that when copying the migrated workflow library into the bin folder, you need to copy the log4net DLLs too.

Migration of existing workflows

Previously a workflow was configured in an .xoml file, for example, the Cart checkout workflow below.

<SequentialWorkflowActivity x:Class="Mediachase.Commerce.Workflow.CartCheckoutWorkflow" x:Name="CartCheckoutWorkflow" xmlns:ns0="clr-namespace:Mediachase.Commerce.Workflow.Activities" xmlns:ns1="clr-namespace:Mediachase.Commerce.Workflow.Activities.Cart" xmlns:ns2="clr-namespace:Mediachase.Commerce.Workflow.Activities.PurchaseOrderActivities" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
<IfElseActivity x:Name="ifElseActivity1">
<IfElseBranchActivity x:Name="ifElseBranchActivity1">
<CodeCondition Condition="RunProcessPayment" />
<ns1:ProcessPaymentActivity Warnings="{x:Null}" OrderGroup="{ActivityBind CartCheckoutWorkflow,Path=OrderGroup}" Payment="{x:Null}" x:Name="processPaymentActivity1" />
<ns0:CalculateTotalsActivity x:Name="calculateTotalsActivity1" OrderGroup="{ActivityBind CartCheckoutWorkflow,Path=OrderGroup}" Warnings="{x:Null}" />
<ns1:AdjustInventoryActivity Description="Adjusts Inventory." x:Name="adjustInventoryActivity1" OrderGroup="{ActivityBind CartCheckoutWorkflow,Path=OrderGroup}" Warnings="{ActivityBind CartCheckoutWorkflow,Path=Warnings}" />
<ns1:RecordPromotionUsageActivity UsageStatus="Used" Warnings="{x:Null}" OrderGroup="{ActivityBind CartCheckoutWorkflow,Path=OrderGroup}" x:Name="recordPromotionUsageActivity1" />

With the new engine a workflow is configured as the activity flow below.

[ActivityFlowConfiguration(Name = OrderGroupWorkflowManager.CartCheckOutWorkflowName)]
public class CartCheckoutActivityFlow : ActivityFlow
{       /// <inheritdoc />       
public override ActivityFlowRunner Configure(ActivityFlowRunner sequence)       
return sequence.If(() => ShouldProcessPayment(sequence.Context))                            
The ActivityFlow name in the ActivityFlowConfiguration should be the Workflow name in the ecf.workflow.config file.

For example, the CartCheckout workflow could be configured as below.

<add name="CartCheckout" displayname="Cart Checkout" description="Processes credit card information"
type="Mediachase.Commerce.Workflow.CartCheckoutWorkflow, Mediachase.Commerce.Workflow" xomlpath="" rulespath="" />

The ActivityFlow name would then be “CartCheckout”.

A workflow property can be removed if used only in Activity. Otherwise, it should be added to the new ActivityFlow, and decorated with the ActivityFlowContextProperty attribute:

public OrderGroup OrderGroup { get; set;}

Note that if a property is marked as a workflow property, it should have a public getter and setter.

Migration of existing activities

To make an existing activity work with the new workflow engine, remove the .Designer.cs file, then modify the code behind as follows:

  • Remove all usages of Microsoft workflow such as: System.Workflow.ComponentModel.CompilerSystem.Workflow.ComponentModel.SerializationSystem.Workflow.ComponentModelSystem.Workflow.ComponentModel.Design and System.Workflow.Runtime.
  • Add references to the new engine: Mediachase.Commerce.WorkflowCompatibility and Mediachase.Commerce.Engine.
  • Remove also the “partial” keyword of the class' declaration, since the .Design.cs file has been removed.
  • If the original activity does not contain the Execute method, then mark the activity’s class as abstract.
  • You may need to remove some invalid attributes marked on properties/events for activities causing the build to fail.

Activity event handling

To declare and raise an event in an activity, call the method RaiseEvent(eventName, eventArgs) in the Execute method of the activity. It is recommended to use a string constant for the event name, as in the example below.

RaiseEvent(ProcessPaymentActivity.ProcessingPaymentEvent, EventArgs.Empty);

To register a handler for the event, call the On method just after registering a step in the activity:

public override ActivityFlowRunner Configure(ActivityFlowRunner sequence)
return sequence.Do<ProcessPaymentActivity>()    
.On(ProcessPaymentActivity.ProcessingPaymentEvent, Notify);

The handler:

private void Notify(object sender, EventArgs arg)
//Do something here

Workflow event handling

Previously, an OrderContext.Current.WorkflowRuntime object was used for listening to a workflow event:

OrderContext.Current.WorkflowRuntime.WorkflowStarted += (obj, e) => {};

In Commerce 9, the WorkflowRuntime property of OrderContext was removed and replaced by the ExecutionManager property.

The example above would then be:

OrderContext.Current.ExecutionManager.ActivityFlowStarted += (obj, e) => {};

Note that the new workflow engine only supports the ActivityFlowStarted and ActivityFlowCompleted events.

Workflow error handling

As before, any exception thrown when executing an activity flow/workflow is kept in WorkflowResults as an Exception property, and does not prevent the program from running.

After migration, you may run into these errors when executing an activity flow:

  • A registered activity flow with a given name does not exist; an ArgumentOutOfRangeException exception is thrown.
  • DuplicatedPropertyException exception is thrown if an activity flow context property is declared in an activity flow (by using the ActivityFlowContextProperty attribute), and also in the different types for the flow’s activities. This happens when the type declared in an activity cannot be converted to the type declared in the activity flow.

See EPiServer Commerce 9 tools and code samples for information about the workflow migration tool and how to use this.


Do you find this information helpful? Please log in to provide feedback.

Last updated: Oct 20, 2016

Recommended reading