Copied to clipboard

Flag this post as spam?

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


  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Jul 23, 2018 @ 15:16
    Bjarne Fyrstenborg
    0

    Casting in GetPropertyValue with Nested Content only works with IEnumerable<IPublishedContent>

    It seems when using GetPropertyValue with Nested Content and using the overload to cast to a specific type T it only work when casting to IEnumerable<IPublishedContent>.

    E.g. if I have some different transport methods in Nested Content, which use a document type Transport then I can get the transport methods with the following code: node.GetPropertyValue<>

    when using ModelsBuilder if would be great to be able to cast this as IEnumerable<Transport> but this will return null.

    node.GetPropertyValue<IEnumerable<Transport>("transportMethods").
    

    and furthermore this also returns null when using OfType:

    node.GetPropertyValue<IEnumerable<IPublishedContent>("transportMethods").OfType<Transport>();
    

    and workaround is to use the following:

    node.GetPropertyValue<IEnumerable<IPublishedContent>("transportMethods").Select(x => new Transport(x));
    

    Not sure if this also is an issue with latest version of Umbraco and Nested Content in core?

    Furthermore if I know node is a specific document type (in my case the property might exists on different node types), I can also cast to this type with ModelsBuilder model and use the property, which return IEnumerable<IPublishedContent>, but it has the same issues, because the property use GetPropertyValue as the example above.

    node.OfType<Destination>().TransportMethods.OfType<Transport>();
    

    If it still is an issue in core, would it be possible to cast this to IEnumerable<T> or/and use OfType<T> on this?

    /Bjarne

  • Paul Wright (suedeapple) 277 posts 704 karma points
    Jul 23, 2018 @ 15:29
    Paul Wright (suedeapple)
    0
    node.GetPropertyValue<IEnumerable<IPublishedContent>("transportMethods").Select(x => new Transport(x));
    

    Is how I do it

    if you have multiple "documenttypes" in your nested content type, then you could return them as IEnumerable of IPublishedContent , and then do a switch to then cast the node to the desired model, based upon its doctypealias

    Takes a bit of tapping on the keyboard to get working, but, well worth it.

          foreach (var module in Model.MyNestedContentModules.OrderBy(x => x.SortOrder))
            {
    
                switch (module.DocumentTypeAlias)
                {
    
                    case "moduleText":
                        @Html.Partial("Modules/Text", new ModuleText(module))
                        break;
    
                    case "moduleTextAndImage":
                        @Html.Partial("Modules/TextAndImage", new ModuleTextAndImage(module))
                        break;
    
                    case "moduleGallery":
                        @Html.Partial("Modules/Gallery", new ModuleGallery(module))
                        break;
    
                    case "moduleLogos":
                        @Html.Partial("Modules/Logos", new ModuleLogos(module))
                        break;
    
                    case "moduleVideo":
                        @Html.Partial("Modules/Video", new ModuleVideo(module))
                        break;
    
                    default:
                        break;
                }
    
    
            }
    
  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Jul 23, 2018 @ 15:47
    Bjarne Fyrstenborg
    0

    That might work well to seperate modules like this, however if the transport methods were different document types, e.g. Car, Bus, Train, Flight you probably just want it as one collection as IEnumerable<IPublishedContent> and loop these and maybe to something specific based on each type. Of course if much of the layout is different depending on each type, it is great to move this stuff to seperate partials.

  • Paul Wright (suedeapple) 277 posts 704 karma points
    Jul 23, 2018 @ 15:56
    Paul Wright (suedeapple)
    0

    My example is purely just trying to demonstrate, how you can roll through the NC, and then assign to a different Model. What you actual do with the "model" is then up to you, and specific to your own needs

    As always with Umbraco - there's 1000000000001 ways to skin a cat.

    Good luck!

  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Jul 23, 2018 @ 16:17
    Bjarne Fyrstenborg
    0

    I know I can create a new model like in the examples, but it doesn't solve my initial question on why this only works when using GetPropertyValue and casting to IEnumerable<IPublishedContent> and OfType<T> only works when T is IPublishedContent.

  • Paul Wright (suedeapple) 277 posts 704 karma points
    Jul 23, 2018 @ 16:21
    Paul Wright (suedeapple)
    0

    This is Umbraco :-)

    You have to expect quirks like this :-)

    I'd questioned more why you are using "GetPropertyValue" still, and not using the ModelsBuilder, which is the way you are shown in the "Umbraco Training".

    Maybe you need to go on some Training? :-)

  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Jul 23, 2018 @ 16:31
    Bjarne Fyrstenborg
    0

    @Paul

    I have been on the training courses.

    and as I mentioned in my initial post, when using a specific property in a ModelsBuilder generated property it actually does use GetPropertyValue under the hood.

    E.g.

    var transportMethods = node.OfType<Destination>().TransportMethods;
    

    in this case the property TransportMethods returns an IEnumerable<IPublishedContent>.

    This is because ModelsBuilder generates this part of the models in DLL mode (which is included in compiled Umbraco.Web.PublishedContentModels.dll) in e.g. /App_Data/Models/Destination.generated.cs:

    [ImplementPropertyType("transportMethods")]
    public IEnumerable<IPublishedContent> TransportMethods
    {
        get { return this.GetPropertyValue<IEnumerable<IPublishedContent>>("transportMethods"); }
    }
    

    So it is the same as using GetPropertyValue<T>.

    Using ModelsBuilder doesn't mean you can't/shouldn't use GetPropertyValue or GetPropertyValue<T> - these methods are still available to use.

  • Lee Kelleher 4020 posts 15802 karma points MVP 13x admin c-trib
    Jul 23, 2018 @ 16:35
    Lee Kelleher
    0

    Hi Bjarne,

    To expand on my "it's more a .NET casting issue" tweet reply...

    There are quite a few things going on here... it can be confusing which bit is doing what. I'll try to explain in due course, but ultimately the specific issue is that .NET can't cast a IEnumerable<IPublishedContent> object to IEnumerable<Transport> object ... it just doesn't know how to do it.


    OK, to walk through what is happening...

    NestedContent's ValueConverter defines what the expected output object-type will be... e.g. typeof(IEnumerable<IPublishedContent>)

    See here: https://github.com/umbraco/Umbraco-CMS/blob/release-7.11.1/src/Umbraco.Web/PropertyEditors/ValueConverters/NestedContentManyValueConverter.cs#L33

    ModelsBuilder explicitly uses this value. Of course, due to the nature of NestedContent, we can't use explicit document-type models, due to polymorphism, etc. The common interface has to be IPublishedContent.
    Keep in mind this is only for ModelsBuilder, (or anything else that uses the GetPropertyValueType call).

    With that said, in NestedContent, it does call the ModelBuilder's factory to get the correct document-type object/model...

    See here: https://github.com/umbraco/Umbraco-CMS/blob/release-7.11.1/src/Umbraco.Web/PropertyEditors/ValueConverters/NestedContentPublishedPropertyTypeExtensions.cs#L114

    Meaning that if you call node.GetPropertyValue<IEnumerable<IPublishedContent>>("transportMethods"), you will actually get a enumerable of Transport objects.


    The issue is now with how to cast them to the appropriate object-type/model - for intellisense, etc.

    I'm not sure why the .OfType<T> extension method doesn't work here. Looking at the source-code, it should be casting accordingly. I guess there must be an upcasting issue?

    https://github.com/Microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs#L1027

    Personally I'd try the .Cast<T> extension method... see if that works?

    Cheers,
    - Lee

  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Jul 23, 2018 @ 16:48
    Bjarne Fyrstenborg
    0

    Hi Lee

    Thank you for your elaboration of this.

    I have tried with .Cast<T> on this:

    var items = node.GetPropertyValue<IEnumerable<IPublishedContent>>("transportMethods");
    var t1 = items.Cast<Transport>();
    var t2 = items.OfType<Transport>();
    

    When outputting .Count() values of t1 and t2, then @t2.Count() returns 0 and @t1.Count() returns an ysod which says Our.Umbraco.NestedContent.Models.DetachedPublishedContent cannot be converted to the type Umbraco.Web.PublishedContentModels.Transport.

  • Lee Kelleher 4020 posts 15802 karma points MVP 13x admin c-trib
    Jul 23, 2018 @ 16:58
    Lee Kelleher
    0

    Bjarne, can I check which version of NestedContent are you using? I'm assuming it's the latest standalone package version, v0.5.0? (which is the version that we ported into Umbraco core).

    If it's an earlier version, than that didn't support ModelsBuilder, it was only introduced in v0.5.0.

  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Jul 23, 2018 @ 17:17
    Bjarne Fyrstenborg
    0

    In the packages.config it has listed v0.3.0

    <package id="Our.Umbraco.NestedContent" version="0.3.0" targetFramework="net452" />
    

    which also match the version number of the assembly Our.Umbraco.NestedContent.dll

    I am not sure if there are some changes in the later versions, which might break some of the existing functionality where it is using Nested Content.

  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Jul 23, 2018 @ 17:30
    Bjarne Fyrstenborg
    0

    Where I think it is a bit inconsistent with Nested Content is for example with OfType extension method.

    E.g. on a destination node I have a MNTP (the legacy one with alias Umbraco.MultiNodeTreePicker) to pick multiple popular hotels.

    I can then use one of the following:

    var destination = node.OfType<Destination>();
    var popularHotels = destination.GetPropertyValue<IEnumerable<IPublishedContent>>("popularHotels").OfType<Hotel>();
    

    or

    var destination = node.OfType<Destination>();
    var popularHotels = destination.PopularHotels.OfType<Hotel>();
    

    with the same .OfType<T> on Nested Content IEnumerable<IPublishedContent> it returns null. (maybe this has been fixed is a newer version of Nested Content or in the core Nested Content).

    However the following also doesn't work the MNTP (I haven't tested this with the newer Umbraco.MultiNodeTreePicker2):

    node.GetPropertyValue<IEnumerable<Hotel>>("popularHotels");
    
  • Lee Kelleher 4020 posts 15802 karma points MVP 13x admin c-trib
    Jul 24, 2018 @ 08:25
    Lee Kelleher
    100

    OK, ModelBuilder support was added to Nested Content in v0.5.0.

    None of this is going to work out-of-the-box with v0.3.0.

    There aren't any breaking-changes between v0.3.0 up to v0.5.0. Here are the release notes for v0.4.0 and v0.5.0.

    If you don't want to upgrade it, then your only option is to do as you already are...

    node.GetPropertyValue<IEnumerable<IPublishedContent>("transportMethods").Select(x => new Transport(x));
    

    I am curious why you're using v0.3.0 - since it was released over 2 years ago. Are you working on old build?

    Cheers,
    - Lee

  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Jul 24, 2018 @ 09:48
    Bjarne Fyrstenborg
    0

    Thanks Lee

    Yes, the project is an older project, which has been upgraded several times and later migrated to Umbraco Cloud.

    I am not sure why the existing Nested Content package hasn't been upgraded to v0.5.0, but it is now running on Umbraco v7.10.4, so Nested Content is included in core and we use this for new properties based on Nested Content and I think we have replaced some of the properties to use the core Nested Content property editor. However some doc types is using the Nested Content package and I think there wasn't an easy way to switch to these to use the core Nested Content without breaking stuff and since many nodes are based on this doc type.

    So I guess that why it still run with the legacy Nested Content package, but I will check if we can upgrade this to v0.5.0 or maybe replace with the core Nested Content package at some point.

    /Bjarne

  • Lee Kelleher 4020 posts 15802 karma points MVP 13x admin c-trib
    Jul 24, 2018 @ 09:57
    Lee Kelleher
    0

    It is possible to hot-swap the package version to the core version, see this thread for details: https://our.umbraco.com/forum/using-umbraco-and-getting-started/90229-migrating-nested-content-to-77#comment-284837

    Note, if you do change the property-editor via the SQL UPDATE, then keep in mind that using Cloud, the Deploy JSON schema files need to be updated too ... I wouldn't suggest doing it manually. I'd probably go via the back-office and re-save the data-types.

  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Jul 24, 2018 @ 10:04
    Bjarne Fyrstenborg
    0

    Thanks for the link and elaboration on how to switch to core Nested Content. We might have a closer look at this at some point, when we do some other updates on the project.

Please Sign in or register to post replies

Write your reply to:

Draft