Setting Complex Model Properties using custom IPropertyValueGetter
Hi Andy,
Thanks for writing this package! It's saved me tons of plumbing code!
I tried to use the IPropertyValueGetter to set a non-primitive property on a model but it was never setting the property.
The use case I have is converting a property that is either from the field (if exists - RJP Url Picker) otherwise fall back to the Url and Name of the content being mapped if the content has a template.
The Property...
[PropertyMapping(PropertyValueGetter = typeof(PromotionLinkPropertyValueGetter))]
public MyViewModels.Link Link { get; set; }
My Property Getter...
public class PromotionLinkPropertyValueGetter : IPropertyValueGetter
{
public object GetPropertyValue(IPublishedContent content, string alias, bool recursive)
{
var rjpLinkCollection = content.GetPropertyValue<IEnumerable<RJP.MultiUrlPicker.Models.Link>>(alias);
var link = rjpLinkCollection?.FirstOrDefault()?.ToMyLink();
if (link != null)
{
return link;
}
link = content.TemplateId > 0 ? content.Map<MyViewModels.Link>() : null;
return link;
}
}
I pulled the code for UmbracoMapper and found due to the destination property being a not simple type it was running a check to see if it was a single or collection of IPublishedContent, I added another check to see if the IPropertyValueGetter was returning a value of type required by the target property, and if so just set that as the value.
https://github.com/AndyButland/UmbracoMapper/blob/master/Zone.UmbracoMapper/UmbracoMapper.cs#L1130
if (value is IPublishedContent)
{
typeof (UmbracoMapper)
.GetMethod("MapIPublishedContent", BindingFlags.NonPublic | BindingFlags.Instance)
.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] {(IPublishedContent) value, property.GetValue(model)});
}
else if (value is IEnumerable<IPublishedContent> && property.PropertyType.GetInterface("IEnumerable") != null)
{
var collectionPropertyType = GetGenericCollectionType(property);
typeof (UmbracoMapper)
.GetMethod("MapCollectionOfIPublishedContent", BindingFlags.NonPublic | BindingFlags.Instance)
.MakeGenericMethod(collectionPropertyType)
.Invoke(this, new object[] {(IEnumerable<IPublishedContent>)value, property.GetValue(model), null});
}
else if (value.GetType().IsAssignableFrom(property.PropertyType))
{
property.SetValue(model, value);
}
Adding the last 4 lines seems to fix it for me.
Thanks again!
Olie
P.S. I thought IMapFromAttribute appeared to be a way to implement custom mapping, but that does not have access to the IPublishedContent, (which I need), only has access to the property value.
Thanks for the suggestions. Looks to me sensible so I'll have a look at adding this to the package shortly (am on holiday for another 10 days or so, so might get to it after that if you don't see an update shortly).
The package has had a few embellishments over the years so there's probably more than one way to do things. Initially I'd probably have tackled what you were looking to do via registering a custom mapping, so you might find that approach works too.
Setting Complex Model Properties using custom IPropertyValueGetter
Hi Andy,
Thanks for writing this package! It's saved me tons of plumbing code!
I tried to use the IPropertyValueGetter to set a non-primitive property on a model but it was never setting the property.
The use case I have is converting a property that is either from the field (if exists - RJP Url Picker) otherwise fall back to the Url and Name of the content being mapped if the content has a template.
The Property...
My Property Getter...
I pulled the code for UmbracoMapper and found due to the destination property being a not simple type it was running a check to see if it was a single or collection of IPublishedContent, I added another check to see if the IPropertyValueGetter was returning a value of type required by the target property, and if so just set that as the value. https://github.com/AndyButland/UmbracoMapper/blob/master/Zone.UmbracoMapper/UmbracoMapper.cs#L1130
Adding the last 4 lines seems to fix it for me.
Thanks again!
Olie
P.S. I thought IMapFromAttribute appeared to be a way to implement custom mapping, but that does not have access to the IPublishedContent, (which I need), only has access to the property value.
Hi Ollie
Thanks for the suggestions. Looks to me sensible so I'll have a look at adding this to the package shortly (am on holiday for another 10 days or so, so might get to it after that if you don't see an update shortly).
The package has had a few embellishments over the years so there's probably more than one way to do things. Initially I'd probably have tackled what you were looking to do via registering a custom mapping, so you might find that approach works too.
Cheers
Andy
If you try the latest version - 2.0.6 - you should find this additional mapping feature you provided is available.
Cheers
Andy
Awesome thanks a bunch Andy!
Cheers, Olie
is working on a reply...