Copied to clipboard

Flag this post as spam?

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


  • Dan Diplo 1554 posts 6205 karma points MVP 5x c-trib
    May 06, 2014 @ 15:52
    Dan Diplo
    0

    Umbraco 6.2.0 PublishedContentExtensions

    I've been upgrading a site from 6.1.6 to 6.2.0 and noticed that the signature for the Where extension on IEnumerable<IPublishedContent> method in Umbraco.Web.PublishedContentExtensions has changed.

    In 6.1.6 there were three, including ones that took a delegate:

    public static IEnumerable<IPublishedContent> Where(this IEnumerable<IPublishedContent> source, Func<IPublishedContent, bool> predicate);
    public static IEnumerable<IPublishedContent> Where(this IEnumerable<IPublishedContent> source, Func<IPublishedContent, int, bool> predicate);
    public static IQueryable<IPublishedContent> Where(this IEnumerable<IPublishedContent> list, string predicate);

    But in 6.2.0 it is now only:

    public static IQueryable<IPublishedContent> Where(this IEnumerable<IPublishedContent> list, string predicate);

    If you use Where in a view then it uses the one from System.Linq.Enumerable instead.

    Is this expected behaviour? And isn't this a breaking change?

  • Stephen 767 posts 2273 karma points c-trib
    May 06, 2014 @ 18:02
    Stephen
    0

    Irks. Should not be the case and would be a breaking change. Having a look.

  • Stephen 767 posts 2273 karma points c-trib
    May 06, 2014 @ 18:21
    Stephen
    100

    OK... both methods are gone in 6.2 because they do not need to be published content extension methods, as they are already native Linq extensions. So if you use System.Linq, both methods should work. Now... might require to recompile the code. Damn. Can share more details on what happens on your side?

  • Dan Diplo 1554 posts 6205 karma points MVP 5x c-trib
    May 06, 2014 @ 21:19
    Dan Diplo
    0

    Thanks, Stephen.

    I noticed it as I had an .ashx handler that dealt with IPublishedContent. In it I had some code like this (where "root" is the homepage of a site):

    var pages = root.Descendants().Where(x => x.DocumentTypeAlias.EndsWith("EventsSection"));

    I noticed VS was underlining the Where part of the query saying something like, "The best overloaded method match for 'Where' has some invalid arguments". In this code I didn't happen to have a reference to System.Linq, so noticed the issue. I then realised that the overload for Where in PublishedContentExtensions was missing the overloads that take Func<IPublishedContent, bool> as an argument and wasn't sure if this was intentional or an oversight.

    Interestingly it never happened in any of the Views or Partials, presumably because the compiler already adds System.Linq namespace, so methods that use "Where" would just fall back to using the standard Linq implementation of Where. And probably most compiled code would also already have a reference to "using System.Linq" as, I think, VS adds this as a default for all new classes. But I guess there could be other cases where code will break if this reference is not there.

    Can I ask: Will the performance of Where queries remain the same using the "native" Linq implementation? I always presumed Umbraco had its own extension methods as these were optimised when dealing with IPublishedContent? Is this not the case? Also, I presume the native Linq methods will produce identical results?

     

  • Stephen 767 posts 2273 karma points c-trib
    May 07, 2014 @ 09:02
    Stephen
    1

    About breaking code: if some code has been compiled (in a DLL) agains the old extension method and you try to run it in 6.2 it will fail and report that the method has not been found - switching to the new method is a compile-time thing that cannot be fixed by the runtime. I hope we won't see too many reports else we'd have to re-introduce the methods in 6.

    As for performances... in fact they should be improved. The native Linq is as fast as it can be and does not add any Umbraco "sugar" on top of it. Which the Umbraco methods did. Mainly to manage "collections of nodes" in order to get things such as content.IsOdd() or content.IsEven() to work. However they were broken anyway. So now we're on bare Linq, and if you need to convert an IEnumerable<IPublishedContent> into a "collection of nodes" where .IsOdd() and .IsEven() works, you need to convert it to a "content set" using .ToContentSet().

    Making sense? Or maybe I need to go into more details?

  • Dan Diplo 1554 posts 6205 karma points MVP 5x c-trib
    May 07, 2014 @ 10:27
    Dan Diplo
    0

    Thanks, Stephen - that makes sense. I'm reassured the "pure" Linq methods are at least as fast, as I didn't want performance to drop. Personally I don't mind recompiling code, but I guess this might need to be made clear in the release notes?

    What is slightly more worrying is that methods such as IsOdd() and IsEven() will stop working. Presumably also IsLast() too (without changing code)? I've got a feeling I may have used these in the past, so that is something to look out for. Again, does sound rather like a breaking change that should be in the release notes? Not a "biggy", though. Thanks :)

  • Stephen 767 posts 2273 karma points c-trib
    May 07, 2014 @ 10:35
    Stephen
    0

    Ah... IsOdd(), IsEven(), IsLast() and anything that relies on Index() do not really "stop working". They were working by accident - and soon as you did anything more complex than enumerating a node's children, they were broken. If you use them outside a ContentSet, they should still work, the way they worked, which is more or less broken. If you use them within a ContentSet, they should work.

    Details: they all use the "index" of the node within the "collection of nodes" to figure out whether the node is odd, even, first or last. The old extension methods tried to maintain a proper "collection of nodes" anytime you filtered it (using Where() etc). This is one of the reason why we had custom extension methods: to try to wrap everything in our own "collection". Was not so good for perfs + wasn't working on complex cases.

    What's done now is, there's no magic to handle a "collection of nodes". The collection a node belongs to is its siblings, ie its parent's children. The "index" always relates to that collection. Unless you convert the enumeration to a content set using .ToContentSet() and then the content set becomes the reference collection.

    To make it short: IsFirst() etc will still work outside of content sets, the way they (sort of) worked. But if you want to be sure they work properly, use a content set.

  • Dan Diplo 1554 posts 6205 karma points MVP 5x c-trib
    May 07, 2014 @ 13:01
    Dan Diplo
    0

    Thanks, Stpehen, makes sense.

    On a different matter, I've found another major breaking change in 6.2.0 which is really weird.

    Take the following simple code where you have a parent page and want to use InGroupsOf() to put the children of the parent page into groups of 2:

    var groups = Model.Content.Children().InGroupsOf(2);

    Now if groups.Count() returned 2 then what would you expect groups.Any() to return? Obviously I would expect it to return true. Prior to 6.2.0 this is what happened. However, now I've found that groups.Any() returns false.

    This is counter-intuitive and a pretty major change as I rely on using groups.Any() to determine whether to show a list of grouped children in a lot of code.

    To get it to work as expected you need to use:

    var groups = Model.Content.Children().InGroupsOf(2).ToList();

    Presumably this forces it into memory, but should this be necessary? Regardless, I think it should work as previously (which is more intuitive).

     

  • Stephen 767 posts 2273 karma points c-trib
    May 07, 2014 @ 13:32
    Stephen
    0

    Mmm.... this is weird. If groups.Count() returns 2 then groups.Any() should be true of course. Looking into it.

  • Stephen 767 posts 2273 karma points c-trib
    May 07, 2014 @ 17:46
    Stephen
    0

    InGroupsOf is not a native Linq extension. It is a method of DynamicPublishedContentList... so I wonder... what exactly is the type of Model.Content in your examples? Is it a dynamic, or an IPublishedContent? What is the type of the Children collection? In fact, unless I miss something, working with pure IPublishedContent then the InGroupsOf extension does just not exist?

  • Dan Diplo 1554 posts 6205 karma points MVP 5x c-trib
    May 07, 2014 @ 18:01
    Dan Diplo
    0

    Yes, InGroupsOf is an extension method in Umbraco.Core.EnumerableExtensions

    The script I have is extremely simple on a fresh Umbraco 6.2.0 install using the standard starter kit:

    The entire script is an MVC partial that looks like this:

    @inherits Umbraco.Web.Mvc.UmbracoTemplatePage
    
    @{
        var groups = Model.Content.Children().InGroupsOf(2);
    
        <h1>Count: @groups.Count() Any?: @groups.Any()</h1>
    
        <p>Model is @Model.GetType()</p>
    
        <p>Model.Content is @Model.Content.GetType()</p>
    
        <p>Model.Content.Children() is @Model.Content.Children().GetType()</p>
    
        <p>groups is @groups.GetType()</p>
    }
    
    This outputs:
    Count: 2 Any?: False
    
    Model is Umbraco.Web.Models.RenderModel
    
    Model.Content is Umbraco.Web.PublishedCache.XmlPublishedCache.XmlPublishedContent
    
    Model.Content.Children() is System.Linq.OrderedEnumerable`2[Umbraco.Core.Models.IPublishedContent,System.Int32]
    
    groups is Umbraco.Core.EnumerableExtensions+InGroupsEnumerator`1+<Groups>d__17[Umbraco.Core.Models.IPublishedContent]

     

     

  • Stephen 767 posts 2273 karma points c-trib
    May 07, 2014 @ 18:01
    Stephen
    0

    Though it would be fairly easy to add the method to IPublishedContent extensions if needed.

  • Stephen 767 posts 2273 karma points c-trib
    May 07, 2014 @ 18:04
    Stephen
    0

    Sorry, my bad. Found the extension method. Looking into it now.

  • Stephen 767 posts 2273 karma points c-trib
    May 07, 2014 @ 18:11
    Stephen
    0

    Reproduced. Bug. Will log into the bug tracked and fix.

    edit: http://issues.umbraco.org/issue/U4-4837

  • Dan Diplo 1554 posts 6205 karma points MVP 5x c-trib
    May 07, 2014 @ 21:02
    Dan Diplo
    0

    Thanks, voted for! 

    Does this mean there will be further 6.2.x patch releases? :)

  • Stephen 767 posts 2273 karma points c-trib
    May 07, 2014 @ 21:32
    Stephen
    1

    @Dan - sounds like it. Mr Project Manager himself says a 6.2.1 is a possible thing. Specifically mentionned you and your missing stuff ;-) So make sure to point me to anything that we thought we could break but after all we accept not to break :-)

Please Sign in or register to post replies

Write your reply to:

Draft