Copied to clipboard

Flag this post as spam?

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


  • Terry Clancy 204 posts 944 karma points
    Sep 15, 2020 @ 17:23
    Terry Clancy
    0

    Descendants in Umbraco 8

    In Umbraco 7 I could use the following code:

    var address = root.Descendants("billing").FirstOrDefault();
    

    Where root is of type IPublished Content.

    The best I could do in Umbraco 8 to do this is the following

    First Inject a Scope Provider as follows:

        public class BillingController : RenderMvcController
        {
    
            private IScopeProvider _scopeProvider;
    
            public BillingController(IScopeProvider scopeProvider)
            {
                _scopeProvider = scopeProvider;
            }
    // ....................................
    }
    

    And then replace the Umbraco 7 line of code with the following:

    Umbraco.Core.Services.IContentService contentService = 
    Services.ContentService;
    long totalRecords = 0;
    IContent address;
    using (var scope = _scopeProvider.CreateScope())
            {
                Umbraco.Core.Persistence.Querying.IQuery<IContent> query = new Query<IContent>(scope.SqlContext).Where(x => x.Name == "billing");
                address = contentService.GetPagedDescendants(root.Id, 0, 100, out totalRecords, query, null).FirstOrDefault();
                //Always complete scope
                scope.Complete();
            }
    

    That seems to be an awful lot of somewhat complex code to replace a single simple line.

    Am I missing something ? Is there a simpler approach ?

    Terry Clancy ClanceZ

  • Marc Goodson 2141 posts 14344 karma points MVP 8x c-trib
    Sep 15, 2020 @ 18:51
    Marc Goodson
    101

    Hi Terry

    There does appear to be some 'Descendants' extension methods for IPublishedContent in V8:

    https://github.com/umbraco/Umbraco-CMS/blob/0886ada39c4651fcd0a8bec5bce4358972791c45/src/Umbraco.Web/PublishedContentExtensions.cs#L869

    Do you need the

    @using Umbraco.Web

    namespace reference in your view/code to be able to discover them?

    regards

    Marc

  • Terry Clancy 204 posts 944 karma points
    Sep 16, 2020 @ 06:03
    Terry Clancy
    0

    Marc,

    Wow, thanks you saved me a lot of time.

    It turns out the my first mistake was to use the following command to get the root content:

    var root = contentService.GetRootContent().FirstOrDefault();

    This returned type IContent rather than IPublishedContent and it was downhill from there because IContent did not have the methods I needed. Furthermore this pitfall is called out explicitly at https://our.umbraco.com/Documentation/Implementation/Services/ as follows:

    Although there is a management Service named the ContentService - only use this to modify content - do not use the ContentService in a View/Template to pull back data to display, this will make requests to the database and be slow - here instead use the generically named UmbracoHelper to access the PublishedContentQuery methods that operate against a cache of published content items, and are significantly quicker.

    Thanks to your response I identified this issue and then with some further work solved as follows:

    I injected UmbracoContext

    public class BillingController : RenderMvcController
    {
    
                public UmbracoContext CatalogContext => ObjectFactory.Instance.Resolve<UmbracoContext>(); 
    
        /........
    }
    

    This is not based on any sample code so I do not know if it is correct, but it satisfies the compiler and I have a more than a thousand errors to resolve in upgrading to Umbraco 8 and Ucommerce 9 before I can test :-)

    Then I was able to use code similar to my original code as follows:

            var root = UmbracoContext.PublishedRequest.PublishedContent.Ancestors().Where(node => node.Name == "Home").FirstOrDefault();
            var address = root.Descendants("billing").FirstOrDefault();
            var nextUrl = address.Url;
    

    Again thanks for you assistance and all the best.

    Terry Clancy ClanceZ

  • Marc Goodson 2141 posts 14344 karma points MVP 8x c-trib
    Sep 16, 2020 @ 07:52
    Marc Goodson
    0

    Hi Terry

    This page in the docs is really helpful for understanding how to access the UmbracoContext in different scenarios:

    https://our.umbraco.com/documentation/Implementation/Services/#accessing-core-services-and-helpers-in-a-controller

    Key thing in your example above you are inheriting from RenderMvcController which automatically gives you reference to the UmbracoHelper and UmbracoContext, and the information you seem to be after, without needing to inject the context!

    public class FlamController : RenderMvcController
    {
        public override ActionResult Index(ContentModel model)
        {
            //RenderMVCController has a static 'UmbracoContext' property
            var homePage = UmbracoContext.Content.GetAtRoot().FirstOrDefault();
            // the ubiquitous UmbracoHelper is always available in a controller inheriting from RenderMvcController
            var queryRoot = Umbraco.ContentAtRoot().FirstOrDefault();
            // when hijacking a route Umbraco passes in a 'ContentModel' containing the current IPublishedContent item
            var currentIPublishedContentItem = model.Content;
            // but also, you can read the AssignedContentItem from the Umbraco Helper...
            var currentUmbracoItem = Umbraco.AssignedContentItem;
    
            return CurrentTemplate(model);
        }
    }
    

    Also as you coming to this with fresh eyes, if you spot things that should be updated in the docs - create an issue on the Docs repo: https://github.com/umbraco/UmbracoDocs so it can be updated to be clearer for people taking on this kind of migration task!

    regards

    Marc

Please Sign in or register to post replies

Write your reply to:

Draft