question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Multiple Media Picker returns list of IPublishedElement

See original GitHub issue

Note: Umbraco HQ has marked this as breaking. Some more info is available below:

Unfortunately fixing this issue led to an unintended breaking change, as you can read below, you will run into this is you are currently querying items picked in a media picker in a strongly typed way, like:

@if (post.PreviewImage != null)
{
     <img src="@post.PreviewImage.GetCropUrl("Blog Preview")" alt="@post.PreviewImage.AltDescription">
}

altDescription in this case is a property on you media type, it could also be the default umbracoWidth property for example.

To fix this, you can update your view in a few different ways:

  1. Use the returned IPublishedContent directly and get the Value for the property like you are used to from other pickers:
@if (post.PreviewImage != null)
{
     <img src="@post.PreviewImage.GetCropUrl("Blog Preview")" alt="@post.PreviewImage.Value("altDescription")">
}
  1. If you enjoy working with strongly typed objects you can cast the item you’re working with to the type you know it should be, for example:
@if (post.PreviewImage is Image previewImage)
{
     <img src="@previewImage.GetCropUrl("Blog Preview")" alt="@previewImage.AltDescription">
}
  1. For you ModelsBuilder lovers, Stéphane has described some additional options here: https://www.zpqrtbnk.net/posts/umbraco-8-1-4-breaking-models-builder/

The original issue description follows:


Hi

When creating a Media Picker data type and setting both “Pick multiple items” and “Pick only images” to true, then it consistently returns IEnumerable<IPublishedElement> instead of IEnumerable<IPublishedContent>.

So if we do a similar setup, like the one in the documentation (https://our.umbraco.com/documentation/Getting-Started/Backoffice/Property-Editors/Built-in-Property-Editors/Media-Picker/) and try to retrieve the value as mentioned in the documentation too, then it will throw an null error.

@{
    var typedMultiMediaPicker = Model.Value<IEnumerable<IPublishedContent>>("sliders");
    foreach (var item in typedMultiMediaPicker)
    {
        <img src="@item.Url" style="width:200px"/>
    }
}

It works just fine in all other combinations, except when the two checkboxes are both set to true.

I have experienced this bug on every Umbraco 8 versions so far.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:10 (10 by maintainers)

github_iconTop GitHub Comments

1reaction
ronaldbarendsecommented, Sep 5, 2019

The following custom PVC makes sure the returned type is set back to Image or IEnumerable<Image> (if ‘Pick only images’ is checked), but now only contains items that actually inherit from this type (as opposed to throwing exceptions):

using System;
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.PropertyEditors;
using Umbraco.Web.PropertyEditors.ValueConverters;
using Umbraco.Web.PublishedCache;

public class CustomMediaPickerValueConverter : MediaPickerValueConverter
{
	private const string ImageTypeAlias = Constants.Conventions.MediaTypes.Image;
	private readonly IPublishedModelFactory _publishedModelFactory;

	public CustomMediaPickerValueConverter(IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedModelFactory publishedModelFactory)
		: base(publishedSnapshotAccessor, publishedModelFactory)
	{
		_publishedModelFactory = publishedModelFactory;
	}

	public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
	{
		var baseType = base.GetPropertyValueType(propertyType);
		if (IsOnlyImagesDataType(propertyType.DataType))
		{
			return (baseType == typeof(IEnumerable<IPublishedContent>))
				? typeof(IEnumerable<>).MakeGenericType(ModelType.For(ImageTypeAlias))
				: ModelType.For(ImageTypeAlias);
		}

		return baseType;
	}

	public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
	{
		var baseSource = base.ConvertIntermediateToObject(owner, propertyType, cacheLevel, source, preview);
		if (IsOnlyImagesDataType(propertyType.DataType))
		{
			var imageType = _publishedModelFactory.MapModelType(ModelType.For(ImageTypeAlias));

			if (baseSource is IEnumerable<IPublishedContent> mediaItems)
			{
				var images = _publishedModelFactory.CreateModelList(ImageTypeAlias);

				foreach (var mediaItem in mediaItems)
				{
					if (mediaItem.GetType().Inherits(imageType))
					{
						images.Add(mediaItem);
					}
				}

				return images;
			}
			else if (baseSource != null)
			{
				return baseSource != null && baseSource.GetType().Inherits(imageType) ? baseSource : null;
			}
		}

		return baseSource;
	}

	private bool IsOnlyImagesDataType(PublishedDataType dataType)
	{
		var config = ConfigurationEditor.ConfigurationAs<MediaPickerConfiguration>(dataType.Configuration);
		return config.OnlyImages;
	}
}

If this class is added to a project, it will automatically be registered and replace the default PVC. This could be a lot cleaner if the default MediaPickerValueConverter is updated with my comments from https://github.com/umbraco/Umbraco-CMS/pull/6034#issuecomment-528327808, but it works and keeps duplicated code to a minimum.

1reaction
ronaldbarendsecommented, Sep 5, 2019

@nul800sebastiaan Make sure to update option 2, as it currently can throw a NullReferenceException if the preview image isn’t of type Image. @NikRimington’s https://github.com/umbraco/Umbraco-CMS/pull/6034#issuecomment-527425298 might also be updated. Better provide correct working examples, especially for the people who like to copy-paste 😉

Using pattern-matching, this can be written as:

@if (post.PreviewImage is Image previewImage)
{
     <img src="@previewImage.GetCropUrl("Blog Preview")" alt="@previewImage.AltDescription">
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Nested Content - Umbraco CMS
This property editor returns either a single item or a collection of this Document Type. The Element Types that Nested Content ...
Read more >
how to pull in multi media picker items
Hi, I've created a document type that, along with other properties (single instance), that contains a list of media items from the multi...
Read more >
How to show umbraco multiple media picker images on ...
Im trying to get images out from a multiple image picker. · If you query the value of the image picker you will...
Read more >
ActiveTopics - RSSing.com
So I have multiple media folders and when going between content sections that have media pickers that are directed to another folder- then...
Read more >
Media picker for photos and videos - .NET MAUI
The IMediaPicker interface has the following methods that all return a FileResult, which can be used to get the file's location or read...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found