Copied to clipboard

Flag this post as spam?

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


  • Jan A 59 posts 264 karma points
    Feb 07, 2023 @ 14:01
    Jan A
    0

    GetValue on property from Content returns null from UmbracoPageController / IVirtualController

    I have a route setup to intercept an url pattern and call a UmbracoPageController (also IVirtualController) From there I identify a published node, get some data from a database and generate the template. Works fine.

    But that template/page use a layout, from where I get a settings node and get the property for my top menu.

    When I debug the node Id is 1074 And if I call this umbracoHelper.Content(1074).GetProperty(PropertyAlias.HeaderMenu).GetValue() I will get null returned

    From a normal page I get the menu.

    If I only call umbracoHelper.Content(1074) I will get the settings node, and GetProperty return the same

    umbracoHelper.Content(1074).GetProperty(PropertyAlias.HeaderMenu)
    "headerMenu" ("AaronSadler.UmbNav")
        Alias: "headerMenu"
        PropertyType: "headerMenu" ("AaronSadler.UmbNav")
        ReferenceCacheLevel: Element
    

    But when I call GetValue it will not work. I have a hard time figuring out why?

  • Jan A 59 posts 264 karma points
    Feb 14, 2023 @ 08:14
    Jan A
    0

    Since I don't get any answers I try to provide some more info and code.

    Basically it is a matter that the AssignedContentItem is not set, but I can't figure out a way around this or to set it.

    Here's the code

    I hijack the route by this code

    u.EndpointRouteBuilder.MapControllerRoute(
    "Category view",
    "/category/{shortname}",
    new { Controller = "Category", Action = "Category" });
    

    Then I have a CategoryController

    public class CategoryController : UmbracoPageController, IVirtualPageController
    {
       public IPublishedContent? FindContent(ActionExecutingContext actionExecutingContext)
        {
            if (_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext))
            {
                var categoryRoot = umbracoContext.Content.GetById(1083); // todo: hämta listnamn
                if (categoryRoot != null)
                {
                    return categoryRoot;
                }
            }
    
            return null;
        } 
    
        public IActionResult Category(string shortname)
        {
            // retrieve data from db etc
            var viewmodel = new MyViewModel();
            return View(viewmodel);
        }
    }
    

    The view then inherits an master template that have the following line

     @(await Component.InvokeAsync("TopNavigation", new { selected = Model.Selected }))
    

    The TopNavigation component looks something like this

    [ViewComponent(Name = "TopNavigation")]
    public class TopNavigationViewComponent : ViewComponent
    {
        private readonly INavigationService navigationService;
    
        public TopNavigationViewComponent(INavigationService navigationService)
        {
            this.navigationService = navigationService;
        }
    
        public IViewComponentResult Invoke(int selected)
        {
            var model = new TopNavigationViewModel()
            {
                Items = this.navigationService.GetTopNavigation(),
            };
            return View(model);
        }
    
    }
    

    The Navigation Service

    public class NavigationService : INavigationService
    {
        private readonly UmbracoHelper umbracoHelper;
        private readonly ISiteSettings siteSettings;
    
        public NavigationService(UmbracoHelper umbracoHelper, ISiteSettings siteSettings)
        {
            this.umbracoHelper = umbracoHelper;
            this.siteSettings = siteSettings;
        }
    
        public List<IPublishedContent> GetSubNavigation(int currentId)
        {
            var currentPage = this.umbracoHelper.Content(currentId);
            var parentOrSelf = currentPage.AncestorOrSelf(2);
            return parentOrSelf.Children?.ToList();
        }
    
        public IEnumerable<UmbNavItem> GetTopNavigation()
        {
            var menu = this.siteSettings.Menu;
            return menu;
        }
    }
    

    And last the site settings. Here I have tried to use IUmbracoContextFactory to retrieve the data without luck. It's the following line

    this.settings.GetProperty(PropertyAlias.HeaderMenu).GetValue() as IEnumerable<UmbNavItem>
    

    that seems to don't have an umbraco context. I thought that using FindContent in IVirtualPageController was used to set the current node, but I suppose it does'nt?

    public class SiteSettings : ISiteSettings
    {
        private readonly UmbracoHelper umbracoHelper;
        private readonly IUmbracoContextFactory umbracoContextFactory;
        private readonly IContentService contentService;
    
        public SiteSettings(UmbracoHelper umbracoHelper, IUmbracoContextFactory umbracoContextFactory, IContentService contentService)
        {
            this.umbracoHelper = umbracoHelper;
            this.umbracoContextFactory = umbracoContextFactory;
            this.contentService = contentService;
        }
    
        private IPublishedContent home => this.umbracoHelper.ContentAtXPath($"//{ContentTypeAlias.Home}")?.FirstOrDefault();
        private IPublishedContent settings  => this.umbracoHelper.ContentAtXPath($"//{ContentTypeAlias.SiteSettings}")?.FirstOrDefault();
    
        public string SiteName => this.home.Name;
    
        public IEnumerable<UmbNavItem> Menu => this.settings.GetProperty(PropertyAlias.HeaderMenu).GetValue() as IEnumerable<UmbNavItem>;
    
    }
    

    So what is the way to accually get the IPublishedContent from that settings when umbracoHelper does not have a Current?

    Calling this will return that Current is null, but only when my custom route is used

    this.settings.GetProperty(PropertyAlias.HeaderMenu).GetValue() as IEnumerable<UmbNavItem>
    Count = 0
        Current: null
        Results View: Expanding the Results View will enumerate the IEnumerable
    

    And I think it's because of AssignedContentItem is not set

    umbracoHelper.AssignedContentItem
    'umbracoHelper.AssignedContentItem' threw an exception of type 
    'System.InvalidOperationException'
    Data: {System.Collections.ListDictionaryInternal}
    HResult: -2146233079
    HelpLink: null
    InnerException: null
    Message: "Cannot return the IPublishedContent because the UmbracoHelper was not constructed with an IPublishedContent."
    Source: "Umbraco.Web.Common"
    StackTrace: "   at Umbraco.Cms.Web.Common.UmbracoHelper.get_AssignedContentItem()"
    TargetSite: {Umbraco.Cms.Core.Models.PublishedContent.IPublishedContent get_AssignedContentItem()}
    
  • Jan A 59 posts 264 karma points
    Feb 14, 2023 @ 10:58
    Jan A
    0

    Ok, more test have been done. I found that HasValue returns true, and if I inspect the value of the property it has a private sourcevalue of

    [{"udi":"umb://document/0dea73210cd349c492846538f436bb33","key":"0dea7321-0cd3-49c4-9284-6538f436bb33","name":"Om oss","description":"/om-oss/","title":"Om oss","url":"/om-oss/","children":[],"icon":"icon-umb-content color-blue","published":true,"naviHide":false,"culture":null,"itemType":"link","id":1075,"collapsed":true},{"udi":"umb://document/bdec7357fd824e36bb112bf0a490614b","key":"bdec7357-fd82-4e36-bb11-2bf0a490614b","name":"Min sida","description":"/min-sida/","url":"/min-sida/","children":[],"icon":"icon-umb-content color-blue","published":true,"naviHide":false,"culture":null,"itemType":"link","id":1080,"collapsed":true}]
    

    So what I did was I created a simple text field in the settings, and I could retrieve that without problem. So it turns out it's not about the context, but about the property somehow.

    The property is of type "AaronSadler.UmbNav" so I guess I may have to look up that implementation?

Please Sign in or register to post replies

Write your reply to:

Draft