Vulnerability in EPiServer.Forms
We use the above method to set various dictionary metadata values; one example in particular is the _ExcludedCatalogEntryMarkets field.
Until either this release, or possibly a slightly older release (not sure as we've only just spotted it), if an empty object was passed in to the 'values' parameter, this would remove any existing values for that field. Now, however, that bahaviour is not exhibited - if an empty object is supplied the method apparently does nothing. This is a problem especially for the _ExcludedCatalogEntryMarkets field if, for example, a product was previously excluded from certain markets, but now we wish to update it to be available everywhere.
The Commerce Manager works as expected so there msut be some way of removing this kind of meta data using the API...?
Note that MetaHelper.SetMetaFieldValue does not really save the value, you should still call metaObject.AcceptChanges() to persist the data.
In your case, try this:
var deletedMarket = new MetaDictionaryItem("MarketId");
var excludedMarkets = marketField.Dictionary.OfType<MetaDictionaryItem>().ToArray();
metaObject["_ExcludedCatalogEntryMarkets"] = excludedMarkets;
This is pseudo code, but you get the idea.
Many thanks for your reply. However I am still experiencing difficulties. In each of the below experiments I have called metaObject.AcceptChanges(metaContext), but in every case no data has changed - the item still retains whatever values it previously has for the _ExcludedCatalogEntryMarkets field.
Please note that we are not deleting any markets from our site; we just want to remove the exclusions from an existing item.
These are the different things I've tried:
List<MetaDictionaryItem> multiValues = new List<MetaDictionaryItem>();
MetaHelper.SetMetaFieldValue(metaContext, metaObject, metaFieldName, multiValues.ToArray());
MetaHelper.SetMetaFieldValue(metaContext, metaObject, metaFieldName, null);
metaObject[metaFieldName] = null;
So far, none of these have worked. The metaField in question does allow nulls. Do you have any other suggestions, or could this be a symptom of a bug?
This is indeed not a bug - as the function is working normally. The code above is not correct, this should do it:
var markets = marketField.Dictionary.OfType<MetaDictionaryItem>().ToList();
var excludedMarkets = markets.Remove(deletedMarket)
You are enabling the metaObject in the "MarketId" here.
Thanks for your help. As it turns out the problem was much more obscure. I had a look at the SQL proc CatalogContentProperty_Save, which is where this information gets saved to the database, and found that the section that deletes MetaField data requires that the language submitted matches the default language of the catalog. However, when updating MetaField data, that supplied language is overwritten by this statement earlier on:
IF @LanguageName NOT IN (SELECT LanguageCode FROM dbo.CatalogLanguage WHERE CatalogId = @catalogId)
SET @LanguageName = (SELECT DefaultLanguage FROM dbo.Catalog WHERE CatalogId = @catalogId)
This corrected @LanguageName parameter is used in the subsequent MERGE statement, but not in the DELETE statement if we are trying to set the MetaField data to NULL.The fix, then, is to ensure the language submitted from the MetaDataContext is the same as the default language of our catalog - en-gb, in our case. As this catalogue updater runs as a console application I needed to explicitly override the default en-us in the program's initialization. Now it works as expected.
Thought this might be useful in case anyone else experiences anything similar!Jim
You should not have to override the default en-us in initialization module. When you load your MetaObject, just make sure to use en-gb in the MetaDataContext, something like this:
var metaDataContext = CatalogContext.MetaDataContext.Clone();
metaDataContext.UseCurrentThreadCulture = false;
metaDataContext.Language = "en-gb";
var metaObject = MetaObject.Load(metaDataContext, ...)
//Update & save it