Empty multi media picker returning {Umbraco.Core.Udi[0]}
Hi,
I'm using Ditto to map to my POCOs and have been really pleased with it so far. I have, however, encountered a problem where empty media pickers are returning an error. We are using the media pickers to allow the client to attach various documents to a product. These may sometimes not contain any documents of that type.
I have a Product page model which has a Technical Documents view model as listed below:
/// <summary>
/// The product page model.
/// </summary>
public class ProductPageModel : BasePageModel
{
/// <summary>
/// Gets or sets the product technical documents.
/// </summary>
[CurrentContentAs]
public virtual TechnicalDocumentsViewModel TechnicalDocuments { get; set; }
...
}
/// <summary>
/// The product technical documents view model.
/// </summary>
public class TechnicalDocumentsViewModel
{
/// <summary>
/// Initializes a new instance of the <see cref="TechnicalDocumentsViewModel"/> class.
/// </summary>
public TechnicalDocumentsViewModel()
{
this.DataSheets = new List<IPublishedContent>();
...
}
/// <summary>
/// Gets or sets the product data sheets.
/// </summary>
public IEnumerable<IPublishedContent> DataSheets { get; set; }
...
}
The error is as follows:
Cannot bind source type Umbraco.Core.Udi[] to model type System.Collections.Generic.IEnumerable`1[[Umbraco.Core.Models.IPublishedContent, Umbraco.Core, Version=1.0.6471.23325, Culture=neutral, PublicKeyToken=null]].
It seems for empty pickers the value is not being converted. Could this be because I'm using the CurrentContentAs attribute? Or is there another reason why I getting this error?
Just to note, I haven't personally used Ditto with the new Udi values yet... so you may well be treading on new ground - prepare yourself for some back & forth on this. :-)
Having a peek at the Umbraco core source, it looks like the issue is with the property-value-converter for the new MediaPicker2 - specifically these lines...
What's happening is that if the converter can't find any media items, it will return an empty array of Udis. Which would then get passed back to Ditto... and Ditto has no idea what to do with it.
On a side note, I can't say that I'm happy that the core value-converter is returning wildly different object-types - makes it difficult to know what we should expect.
Though it looks like someone else raised an issue about it, #U4-10160 + comments on the PR, which got rejected.
If it returned null, then Ditto could handle that scenario.
So in order to fix this, either a custom Ditto processor or a generic .NET TypeConverter would need to be created... (or potentially a PR/update to Ditto's UmbracoPicker processor?)
Just had an alternative idea... by replacing the core's MediaPickerPropertyConverter with your own.
So you'd have a start-up event to remove the registered value-converter and your own version would then be used.
Here's some example code...
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.PropertyEditors.ValueConverters;
namespace Our.Umbraco.Ditto.Examples
{
public class Bootstrapper: ApplicationEventHandler
{
protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
PropertyValueConvertersResolver.Current.RemoveType<MediaPickerPropertyConverter>();
}
}
public class MyMediaPickerPropertyConverter: MediaPickerPropertyConverter
{
public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
{
var value = base.ConvertSourceToObject(propertyType, source, preview);
if (value is Udi[])
{
return GetPropertyValueType(propertyType).GetDefaultValue();
}
return value;
}
}
}
Please note, I haven't tried or tested this... you may have to play around with it to get it to work for your project.
Sorry for the late reply I'm a bit swamped at work at the moment. After reading thorugh the resources you've linked to I have to agree that I think the return type should be the default of the requested type. If the property converter doesn't know how to convert it or it's empty then the default value should be returned. Otherwise my application is going to break!
I'm still getting to grips with Umbraco, this being my first project, so I wouldn't want to suggest a solution but for the time being creating the custom MediaPickerPropertyConverter has worked a treat.
Thanks for your time, I'll go with this solution and keep an eye on any changes in the source code.
Could I maybe get some help with this same issue - my back end skills are not the best so I am having a bit of trouble understanding the solution Lee suggested.
I initially had a MultimediaPicker field set to the following property on my model:
[UmbracoPicker]
public IEnumerable<ImageModel> Images { get; set; }
The ImageModel
[UmbracoPicker]
public class ImageModel
{
[UmbracoProperty("umbracoWidth")]
public virtual int Width { get; set; }
[UmbracoProperty("umbracoHeight")]
public virtual int Height { get; set; }
public string Name { get; set; }
public virtual int Id { get; set; }
public virtual string Url { get; set; }
[UmbracoProperty("umbracoBytes")]
public virtual int Size { get; set; }
[UmbracoProperty("umbracoExtension")]
public virtual int Type { get; set; }
[UmbracoProperty("type")]
public string FileType { get; set; }
}
On a previous version of umbraco ditto (0.10.0) this mapping would work fine and all media items would get converted into ImageModels, however, now I can only get it to work if on my main Model I change the IEnumerable to:
[UmbracoPicker]
public IEnumerable<IPublishedContent> Images { get; set; }
Any suggestions to fix this? Or maybe a few more steps to implement the solution proposed? (should I downgrade Umbraco Ditto?)
i'm running my images through a processor as i'm setting the absolute url so my set up is slightly different but this was my 'hack' way round the problem:
public class ImagePickerAttribute : DittoProcessorAttribute
{
private readonly HttpContextBase _httpContext;
private readonly IModelConverter _modelConverter;
public ImagePickerAttribute()
{
_httpContext = DependencyResolver.Current.GetService<HttpContextBase>();
_modelConverter = DependencyResolver.Current.GetService<IModelConverter>();
}
public ImagePickerAttribute(HttpContextBase httpContext, IModelConverter modelConverter)
{
_httpContext = httpContext;
_modelConverter = modelConverter;
}
public override object ProcessValue()
{
if (string.Equals(Value?.ToString(), "Umbraco.Core.Udi[]", StringComparison.CurrentCultureIgnoreCase))
{
return null;
}
var image = _modelConverter.ToModel<MediaImageModel>((IPublishedContent)Value);
image.UrlAbsolute = _httpContext?.Request.Url == null ? image.Url : $"{_httpContext.Request.Url.GetLeftPart(UriPartial.Authority)}{image.Url}";
return image;
}
}
feels kinda stinky but it does work! what i can't figure out is why umbraco is changing it's return type i.e. if no image is selected you get 'Umbraco.Core.Udi[]' and if an image is selected you get a piece of IPublishedContent?
Personally, I don't understand the logic behind it. I've tried to have a discussion about it, but unfortunately the conclusion came to it'd would be a breaking-change.
Empty multi media picker returning {Umbraco.Core.Udi[0]}
Hi,
I'm using Ditto to map to my POCOs and have been really pleased with it so far. I have, however, encountered a problem where empty media pickers are returning an error. We are using the media pickers to allow the client to attach various documents to a product. These may sometimes not contain any documents of that type.
I have a Product page model which has a Technical Documents view model as listed below:
The error is as follows:
It seems for empty pickers the value is not being converted. Could this be because I'm using the CurrentContentAs attribute? Or is there another reason why I getting this error?
Any help would be appreciated.
Thanks,
Andy
Hi Andy,
Which version of Umbraco are you using?
Just to note, I haven't personally used Ditto with the new
Udi
values yet... so you may well be treading on new ground - prepare yourself for some back & forth on this. :-)Having a peek at the Umbraco core source, it looks like the issue is with the property-value-converter for the new MediaPicker2 - specifically these lines...
https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerPropertyConverter.cs#L171-L201
What's happening is that if the converter can't find any media items, it will return an empty array of
Udi
s. Which would then get passed back to Ditto... and Ditto has no idea what to do with it.If it returned
null
, then Ditto could handle that scenario.So in order to fix this, either a custom Ditto processor or a generic .NET TypeConverter would need to be created... (or potentially a PR/update to Ditto's
UmbracoPicker
processor?)How are your C# skills? :-)
Cheers,
- Lee
Just had an alternative idea... by replacing the core's
MediaPickerPropertyConverter
with your own.So you'd have a start-up event to remove the registered value-converter and your own version would then be used.
Here's some example code...
Please note, I haven't tried or tested this... you may have to play around with it to get it to work for your project.
Cheers,
- Lee
Hi Lee,
Sorry for the late reply I'm a bit swamped at work at the moment. After reading thorugh the resources you've linked to I have to agree that I think the return type should be the default of the requested type. If the property converter doesn't know how to convert it or it's empty then the default value should be returned. Otherwise my application is going to break!
I'm still getting to grips with Umbraco, this being my first project, so I wouldn't want to suggest a solution but for the time being creating the custom MediaPickerPropertyConverter has worked a treat.
Thanks for your time, I'll go with this solution and keep an eye on any changes in the source code.
Andy
Hi Andy,
Welcome to Umbraco! Despite minor API things like this, it really is an awesome CMS, (that's why I'm still using it for 10 years now).
(I was a little worried that my initial reply got a bit tech heavy and negative)
The beauty of open-source is that we can figure these things out as a community... so always feel free to ask any questions you have.
Cheers,
- Lee
Hey Lee,
I love the tech, I've been in the industry for 15 years! But I think it's a little early for me to speak with any authority about Umbraco. :)
I'm certainly enjoying Umbraco so far and will hopefully be able to contribute in the future.
Thanks again.
Andy
Hi Andy and Lee,
Could I maybe get some help with this same issue - my back end skills are not the best so I am having a bit of trouble understanding the solution Lee suggested.
I initially had a MultimediaPicker field set to the following property on my model:
The ImageModel
On a previous version of umbraco ditto (0.10.0) this mapping would work fine and all media items would get converted into ImageModels, however, now I can only get it to work if on my main Model I change the IEnumerable to:
Any suggestions to fix this? Or maybe a few more steps to implement the solution proposed? (should I downgrade Umbraco Ditto?)
Thank you, Paciencia
Hey Paciencia,
Try removing the
[UmbracoPicker]
attribute from theImages
property.Since it's on the
ImageModel
class, then Ditto would use it.Let me know if that works for you.
Cheers,
- Lee
chiming in a bit late on this one but i've just hit the exact same problem with a new site i'm working on...
i've created a datatype based on the 'Media Picker' property editor (MediaPicker2) but set it so it can only pick a single image (which according to https://our.umbraco.org/documentation/getting-started/backoffice/property-editors/built-in-property-editors/Media-Picker2 should return a single item of IPublishedContent.
i'm running my images through a processor as i'm setting the absolute url so my set up is slightly different but this was my 'hack' way round the problem:
feels kinda stinky but it does work! what i can't figure out is why umbraco is changing it's return type i.e. if no image is selected you get 'Umbraco.Core.Udi[]' and if an image is selected you get a piece of IPublishedContent?
tricky...
Yup, confusing isn't it?!
It's all in the value-converter for the MediaPicker2: https://github.com/umbraco/Umbraco-CMS/blob/release-7.9.2/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerPropertyConverter.cs#L171-L201
Personally, I don't understand the logic behind it. I've tried to have a discussion about it, but unfortunately the conclusion came to it'd would be a breaking-change.
is working on a reply...