Deleting Media Assets Episerver Commerce
How to delete and update commerce media assets properly.
Published 30 dec 2020
Episerver Commerce 10 to 13
“Media not found”
This happens when the image is deleted from the CMS media but still linked in the Commerce Media Asset Pane UI.
Why? because it is possible to delete the image with code, without getting the warning like you get from the UI.
Still you can “move to trash” and empty trash bin, then you get “Media not found” in commerce media assets.
Error: “Navigate to Assets tab and remove it in order to publish”
“System.ComponentModel.DataAnnotations.ValidationException: Media is not found. Navigate to Assets tab and remove it in order to publish.” – you get this error if you try to publish the catalog item, when item has an linked asset that is deleted from media pane. The message explains how to solve it manually in the UI.
How to avoid the error – unlink media
The trick is to unlink the media asset before you delete it.
If you are working from code, you may find the use of the media with GetReferencesToContent on IContenRepository
Example GetReferencesToContent:
var refList = _contentRepository.GetReferencesToContent(existingMediaData.ContentLink, false);
foreach (var item in refList)
{
if (UnLinkCommerceMedia(item.OwnerID, existingMediaData.ContentLink))
Example UnLinkCommerceMedia method:
private bool UnLinkCommerceMedia(ContentReference parentContentReference, ContentReference mediaReference)
{
IAssetContainer writableContent = null;
if (_contentRepository.TryGet(parentContentReference, out NodeContent nodeContent))
{
writableContent = nodeContent.CreateWritableClone<NodeContent>();
}
else if (_contentRepository.TryGet(parentContentReference, out EntryContentBase catalogEntry))
{
writableContent = catalogEntry.CreateWritableClone<EntryContentBase>();
}
if (writableContent == null)
return false;
var writableMediaCollection = writableContent.CommerceMediaCollection.CreateWritableClone();
var mediaToRemove = writableContent.CommerceMediaCollection.FirstOrDefault(x => x.AssetLink.Equals(mediaReference));
if (mediaToRemove == null)
return false;
writableContent.CommerceMediaCollection.Remove(mediaToRemove);
_contentRepository.Save((IContent)writableContent, SaveAction.Publish | SaveAction.SkipValidation, AccessLevel.NoAccess);
return true;
}
Example how to remove “media not found” on commerce media collection
//if image been delete the media is linked with status "Media not found" in UI - then need to be removed, else it will throw System.ComponentModel.DataAnnotations.ValidationException: Media is not found. Navigate to Assets tab and remove it in order to publish. at EPiServer.Core.ContentProvider.ThrowValidationException(ICollection`1 errors) at EPiServer.Core.Internal.DefaultContentRepository.Save(IContent content, SaveAction action, AccessLevel access)
var unlinkedAssets = writableContent.CommerceMediaCollection.Where(x => ContentReference.IsNullOrEmpty(x.AssetLink)).ToList();
foreach (var asset in unlinkedAssets)
{
writableContent.CommerceMediaCollection.Remove(asset);
}
Example “Attach media to commerce items”:
/// <summary>
/// Adding media to Commerce Items, blog: https://devblog.gosso.se/?p=1506
/// </summary>
/// <param name="contentMedia">The IContentMedia</param>
/// <param name="codes">Commerce Codes</param>
private void AddLinksFromMediaToCodes(MediaData contentMedia, List<EntryCode> codes)
{
var media = new CommerceMedia { AssetLink = contentMedia.ContentLink, GroupName = "default", AssetType = "episerver.core.icontentmedia" };
foreach (EntryCode entryCode in codes)
{
var contentReference = _referenceConverter.GetContentLink(entryCode.Code);
IAssetContainer writableContent = null;
if (_contentRepository.TryGet(contentReference, out EntryContentBase entry))
writableContent = (EntryContentBase) entry.CreateWritableClone();
if (_contentRepository.TryGet(contentReference, out NodeContent node))
writableContent = (NodeContent)node.CreateWritableClone();
if (writableContent == null)
{
_logger.Error($"Can't get a suitable content (with code {entryCode.Code} to add CommerceMedia to, meaning it's neither EntryContentBase nor NodeContent.");
continue;
}
//remove if already connected
var existingMedia = writableContent.CommerceMediaCollection.FirstOrDefault(x => x.AssetLink.Equals(media.AssetLink));
if (existingMedia != null)
writableContent.CommerceMediaCollection.Remove(existingMedia);
//if image been delete the media is linked with status "Media not found" in UI - then need to be removed, else it will throw System.ComponentModel.DataAnnotations.ValidationException: Media is not found. Navigate to Assets tab and remove it in order to publish. at EPiServer.Core.ContentProvider.ThrowValidationException(ICollection`1 errors) at EPiServer.Core.Internal.DefaultContentRepository.Save(IContent content, SaveAction action, AccessLevel access)
var unlinkedAssets = writableContent.CommerceMediaCollection.Where(x => ContentReference.IsNullOrEmpty(x.AssetLink)).ToList();
foreach (var asset in unlinkedAssets)
{
writableContent.CommerceMediaCollection.Remove(asset);
}
if (entryCode.IsMainPicture)
{
_logger.Debug($"Setting '{contentMedia.Name}' as main media on {entryCode.Code}");
media.SortOrder = 0; // because the first image is the main image
writableContent.CommerceMediaCollection.Insert(0, media);
}
else
{
_logger.Debug($"Adding '{contentMedia.Name}' as media on {entryCode.Code}");
media.SortOrder = 1;
writableContent.CommerceMediaCollection.Add(media);
}
try
{
//use SaveAction.SkipValidation flag more performant
_contentRepository.Save((IContent)writableContent, SaveAction.Publish | SaveAction.SkipValidation, AccessLevel.NoAccess);
}
catch (Exception e)
{
//Importing resource failed: System.ComponentModel.DataAnnotations.ValidationException: Media is not found. Navigate to Assets tab and remove it in order to publish. at EPiServer.Core.ContentProvider.ThrowValidationException(ICollection`1 errors) at EPiServer.Core.Internal.DefaultContentRepository.Save(IContent content, SaveAction action, AccessLevel access)
_logger.Error($"Something went wrong connecting assets code: {entryCode.Code} cr: {contentReference.ID}, media: {media.AssetLink.ID} {contentMedia.Name}. Continuing... ", e);
continue;
}
}
}
public class EntryCode
{
public string Code { get; set; }
public bool IsMainPicture { get; set; }
}
Related links
- https://world.episerver.com/forum/developer-forum/Episerver-Commerce/Thread-Container/2020/3/commercemedianotfound-exception-thrown-when-trying-to-publish-variant-using-contentrepository/
- https://support.episerver.com/hc/en-us/articles/115003738211-Deleting-CommerceMedia-leaves-the-asset-row-intact
- https://world.episerver.com/documentation/Release-Notes/ReleaseNote/?releaseNoteId=123242
- https://world.episerver.com/forum/developer-forum/Episerver-Commerce/Thread-Container/2020/10/media-not-found—how-to-delete-and-find-the-media-relation-in-later-version-of-commerce/
About the author
Luc Gosso
– Independent Senior Web Developer
working with Azure and Episerver
Twitter: @LucGosso
LinkedIn: linkedin.com/in/luc-gosso/
Github: github.com/lucgosso