Optimizely batch publish gotcha
Hiya!
Today's post is about a TIL and a little gotcha I ran into while migrating Commerce properties. Never seen this exact issue before in my 10 years working with Episerver/Optimizely, so as a friendly coder, I leave this post for posterity and search engines.
The issue rose as I renamed, made culture specific and switched types for a couple of properties.
As we have quite a few versions in our catalog I opted for the new(ish) extension method
for IContentRepository
which takes a collection of content items to batch publish.
I did some testing versus just plain iterating through all content and publishing one by one,
running in batch was way faster. The code that did not work as expected below.
private void Migrate(IContentRepository contentRepository)
{
List<MyVariationContent> writableItems = GetWritableClones();
contentRepository.Publish(writableItems);
}
So far so good. My preliminary tests went fine. Code review went fine. UAT went fine. The day of production release comes. Everything works fine there as well. Until... I noticed that the property values were not populated in the Commerce Catalog UI. When working through the API it's all there as expected but somewhere along the way to the admin UI it gets lost. Querying the CatalogEntry table and meta class view shows it all being present. What the heck?
Those of you that have read the documentation (I thought I had) may have noticed that for the batch
method it says that it will bypass some versioning features etc. One effect of this is that updates for
commerce content is not replicated into the versioning tables for commerce (ecfVersion, ecfVersionProperty).
As the UI reads from these tables they fetch stale data which will result in overwrite if touched and saved in
the editorial interface.
One overload for the Publish method takes in a PublishAction
enum value, which is either None
or SyncDraft
.
I initially used the former for migrating my content properties. Using the latter in a second migration seems to
correctly migrate the updated property values into the version tables, thereby keeping the UI in sync with
the information in the main commerce tables. The barely modified code below.
private void Migrate(IContentRepository contentRepository)
{
List<MyVariationContent> writableItems = GetWritableClones();
contentRepository.Publish(writableItems, PublishAction.SyncDraft);
}
While trying to work out where things went wrong I looked into database and API both. Below is kind of what the UI client side scripts are hitting when fetching the property information from backend through the metadata rest store. Not really relevant for the solution but still a good check on what and where data is resolved. The actual content link value that you are looking at can be found through the browser network tab as a query param to the store/metadata endpoint.
private void Foo()
{
// Get services etc from container
var locator = ServiceLocator.Current;
var metaDataProvider = locator.GetInstance<ExtensibleMetadataProvider>();
var modelCreator = locator.GetInstance<IMetadataStoreModelCreator>();
// The code
var type = TypeResolver.GetType("EPiServer.Core.ContentData");
var args = new Dictionary<string, string> { { "contentLink", "12345_779113_CatalogContent" } };
var accessor = metaDataProvider.MetadataHandlerRegistry.GetModelAccessor(type, args);
var metaData = metaDataProvider.GetMetadataForType(accessor, type);
var uiModel = modelCreator.Create(metaData);
// Here the store would return a JSON payload to the frontend
}
Cheers!