Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Al Burns 49 posts 149 karma points
    Mar 08, 2016 @ 13:23
    Al Burns
    0

    UmbracoMapper custom mapping not working with Umbraco 7.4.1

    Hi.

    I am trying to get UmbracoMapper to work with mapping a related links data type using a custom mapping. My code is as follows:

    Models:

    public class HomeViewModel
    {
        public IEnumerable<NavLink> NavigationLinks { get; set; }
    }
    
    public class NavLink
    {
        public string Title { get; set; }
        public string Caption { get; set; }
    
        [JsonProperty("type")]
        public string LinkType { get; set; }
    
        public bool NewWindow { get; set; }
        public bool IsInternal { get; set; }
        public string Link { get; set; }
        public string InternalName { get; set; }
    }
    

    Mapper use:

    var mapper = new UmbracoMapper();
    mapper.AddCustomMapping(typeof(IEnumerable<NavLink>).FullName, MapRelatedLinksContent);
    
    var viewModel = new HomeViewModel();
    mapper.Map(CurrentPage, viewModel);
    

    Mapping method:

    public static object MapRelatedLinksContent(IUmbracoMapper mapper, IPublishedContent contentToMapFrom, string propName, bool isRecursive)
    {
        string relatedLinks = contentToMapFrom.GetPropertyValue<string>(propName, isRecursive);
        return JsonConvert.DeserializeObject<IEnumerable<NavLink>>(relatedLinks);
    }
    

    This works perfectly well using Umbraco 7.3.4, but when I try the same code in Umbraco 7.4.1 the following exception is thrown on the mapper.Map() line:

    An exception of type 'System.ArgumentException' occurred in mscorlib.dll but was not handled in user code

    Additional information: Object of type 'Newtonsoft.Json.Linq.JArray' cannot be converted to type 'System.Collections.Generic.IEnumerable`1[Test_UmbracoMapper.Models.NavLink]'.

    Any help with resolving this issue or a working example for Umbraco 7.4.1 would be appreciated.

    Many thanks.

  • Martin Almström 33 posts 159 karma points
    Mar 08, 2016 @ 14:50
    Martin Almström
    0

    Hi,

    Have you tried deserializing to a List<> instead?

    public static object MapRelatedLinksContent(IUmbracoMapper mapper, IPublishedContent contentToMapFrom, string propName, bool isRecursive)
    {
        string relatedLinks = contentToMapFrom.GetPropertyValue<string>(propName, isRecursive);
        return JsonConvert.DeserializeObject<List<NavLink>>(relatedLinks);
    }
    

    Could be that newtonsoft json cannot convert to an interface (IEnumerable<>) and need the implemented class (List or equal)

    /Martin

  • Al Burns 49 posts 149 karma points
    Mar 08, 2016 @ 14:55
    Al Burns
    0

    Hi Martin.

    The JsonConvert operation works fine with IEnumerable as just running the following results in a properly deserialised collection (I have tested this in isolation):

    string relatedLinks = CurrentPage.GetPropertyValue<string>("navigationLinks");
    var result = JsonConvert.DeserializeObject<IEnumerable<NavLink>>(relatedLinks);
    
  • Andy Butland 422 posts 2333 karma points MVP 4x hq c-trib
    Mar 08, 2016 @ 18:41
    Andy Butland
    0

    Not sure is the quick but not very useful reply Al. But just wanted to respond to say I'll take a look at this later this week, as am away at the moment. Wasn't aware of any compatibility changes with Umbraco 7.4 but could be you've found one.

    Andy

  • Al Burns 49 posts 149 karma points
    Mar 09, 2016 @ 08:41
    Al Burns
    0

    OK, great. Thanks Andy.

    If it's any use, I also tried mapping an Archetype property following the method detailed in this article

    I got a similar exception thrown when calling the Map method. It didn't even get into the custom mapping method as I put a breakpoint in the method which was never hit.

    Al

  • Andy Butland 422 posts 2333 karma points MVP 4x hq c-trib
    Mar 10, 2016 @ 22:33
    Andy Butland
    0

    I've figured out the issue now Al, it's due to the fact that with Umbraco 7.4 we now have the "Models Builder" shipped with the core product and enabled by default. You should be able to get things working again just by disabling this, via the following web.config setting:

    <add key="Umbraco.ModelsBuilder.Enable" value="false" />
    

    The reason this being enabled is causing a problem for Umbraco Mapper is that this package is all about mapping from IPublishedContent items. It looks first for any native properties - existing strongly typed fields (e.g. Id, Name, Url) - and maps those. And then it handles the custom fields you've created on the document type.

    With models builder set up, then you would already have strongly typed fields being generated, and Umbraco Mapper is then attempting to map those as if they were all native properties. For primitive types like strings and numbers it would do so successfully, but for related links (and others like Archetype where a chunk of JSON is used), it's trying to map a JArray to an IEnumerable and not succeeding.

    So could this be made to work? Possibly, but I'm not sure it's a good idea - though would be interested in others opinions on this.

    I would suggest Umbraco Mapper (or I imagine Ditto which I believe is similar in it's approach to mapping to view models) can certainly still be used with Umbraco 7.4 onwards, but I'm not convinced it makes sense to use them as well as Models Builder.

    For me I'd suggest one of two approaches should be used.

    1. Turn Models Builder off and continue using Umbraco Mapper or Ditto to map from IPublishedContent to strongly typed view models. I still like this approach over Models Builder on it's own as then our views are working with true view models and not just representations of a single document type (which are strongly typed, but don't account for anything else we might want in the view, like information drawn from other content nodes). For me this would be the equivalent in a standard MVC application of passing our "domain" model to our view, which is often considered something best avoided.

      1. Decide we like the strongly typed content models over IPublishedContent but then still maintain a distinction between these and the view models. We then need a method of mapping from one strongly typed model to the other, for which I'd likely look to use AutoMapper, which is much better established in this space and by this point there's nothing Umbraco specific that needs doing.

    I discussed this distinction a couple of years back in this blog post if interested in reading further.

    I'll probably expand on this at some point in another blog post or something - and as I say, interested in other opinions on this - but meantime, the short answer is I don't suspect if you are using Umbraco Mapper you are also using Models Builder, and if not, you can just turn the latter off.

    Andy

  • Al Burns 49 posts 149 karma points
    Mar 11, 2016 @ 08:44
    Al Burns
    0

    Hi Andy.

    I would certainly like to use Umbraco Mapper as we want to go down the strongly typed view route with our Umbraco projects. I'll discuss with our team here but will most likely disable Models Builder as suggested.

    Many thanks for the swift reply, it's good that there looks to be a resolution for this.

    Al

Please Sign in or register to post replies

Write your reply to:

Draft