Copied to clipboard

Flag this post as spam?

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


  • Daniel Chenery 119 posts 465 karma points
    Feb 09, 2016 @ 16:07
    Daniel Chenery
    0

    Cannot render a macro when there is no current PublishedContentRequest (Custom Controller/Model)

    Hi,

    I'm sure this is a familiar issue - I've found threads with the same problem, but unfortunately not fix it for me.

    I'm also aware I can use [EnsurePublishedContentRequest(Id)], but unfortunately that solution also isn't available to me here.

    As a quick overview, I'm using Umbraco as the 'Core' of my website, where some pages are dynamically generated via an API.

    On an API generated page, I need to ability to add macros which is causing the above error. Any help would be very appreciated, it may well even be something very obvious that I've missed!

    Controller:

    public class ApiPageController : RenderMvcController
    {
        public ActionResult Item(RenderModel model, string apiId)
        {
            // connect to the API and get the item page
            var api = new ApiConnection();
            var apiResult = api.getPage(apiId);
    
            UmbracoHelper UH = new UmbracoHelper(UmbracoContext.Current);
            var UmbracoApiPage = UH.TypedContentAtRoot()
                .DescendantsOrSelf("ApiContent")
                    .Where(pc => pc.GetPropertyValue("apiId") != null)
                    .FirstOrDefault();
    
            var vm = new ApiViewModel(UmbracoApiPage, CultureInfo.CurrentUICulture);
    
            // RouteData.DataTokens["umbraco"] = vm;
            // RouteData.DataTokens["umbraco-doc-request"] = UmbracoContext.Current.PublishedContentRequest;
            // RouteData.DataTokens["umbraco-context"] = UmbracoContext.Current;
    
            // assign the page to the View Model
            vm.apiPage = apiResult;
    
            return View(vm);
        }
    }
    

    Model:

    public class ApiViewModel : RenderModel
    {   
        // Not used, left in as a fallback
        public ApiViewModel() : this(new UmbracoHelper(UmbracoContext.Current)) { }
    
        // Not used, left in as a fallback
        public ApiViewModel(UmbracoHelper Umbraco)
            : this(Umbraco.TypedContentAtRoot().FirstOrDefault(), CultureInfo.CurrentUICulture)
        {
        }
    
        public ApiViewModel(IPublishedContent content, CultureInfo culture)
            : base(content, culture)
        {
            // Dummy constructor
        }
    
        public ApiPageResult ApiPage { get; set; }
    }
    

    If believe that's the code you need to see, but let me know if you need snippets of the View :)

    Thanks,

    Daniel

  • Daniel 60 posts 174 karma points
    Feb 09, 2016 @ 17:50
    Daniel
    0

    A small thing I see is:

    UmbracoHelper UH = new UmbracoHelper(UmbracoContext.Current);
    var UmbracoApiPage = UH.TypedContentAtRoot().DescendantsOrSelf("ApiContent")
        .Where(pc => pc.GetPropertyValue("apiId") != null).FirstOrDefault();
    

    You should be able to just do:

    var UmbracoApiPage = Umbraco.TypedContentAtRoot().DescendantsOrSelf("ApiContent")
        .Where(pc => pc.GetPropertyValue("apiId") != null).FirstOrDefault();
    

    Regarding your problem, I think you may just need to replace your 3 constructors in your ViewModel with 1:

    public ApiViewModel() : base(UmbracoContext.Current.PublishedContentRequest.PublishedContent) { }
    

    Also are you following the route naming convention?

    • A document type with alias "ApiPage"
    • A template with alias "Item"

    And I assume your view ("Item.cshtml") probably starts with:

    @inherits UmbracoViewPage<ApiViewModel>
    

    If you're following the standard routes, instead of

    return View(vm)
    

    You should be able to do:

    return CurrentTemplate(vm);
    

    Also, I'm not sure your ActionResult constructor is ok, but that's just because I've never tried, maybe your way is fine! A thing I know should work would be:

    public ActionResult Item(ApiViewModel model)
    {
        var apiId = Request["apiId"];
        ....null check etc. //then you can do:
        model.ApiPage = new ApiConnection().getPage(apiId)
    
  • Daniel Chenery 119 posts 465 karma points
    Feb 10, 2016 @ 08:59
    Daniel Chenery
    0

    Hi Daniel,

    Regarding the creating a new UmbracoHelper, the only reason I'd opted for this method is because doing Umbraco.TypedContentAtRoot() etc... resulted in the following error:

    DataTokens must contain an 'umbraco-doc-request' key with a PublishedContentRequest object

    Unfortunately, I'm still given the same error with the changes above implemented.

    I implemented the new ViewModel constructor, but I'm afraid UmbracoContext.Current.PublishedContentRequest is null :(

    In regards to your other questions:

    • There is no document type with an alias of "ApiPage" - I didn't think it was required since these pages or dynamically generated
    • I do have a template called "Item"
    • The view page does have @inherits UmbracoViewPage<ApiViewModel> at the top

    The ActionResult constructor is working, but I have a custom route setup in Global.asax :)

    Thanks,

    Daniel

  • Daniel Chenery 119 posts 465 karma points
    Feb 21, 2017 @ 09:04
    Daniel Chenery
    101

    For anyone else that has this issue, I've found a fix. Instead of inheriting from RenderModel I had to create a custom model which initiated the PublishedContentRequest (based off the EnsurePublishedContentRequest attribute).

    Making custom models inherit from this appears to have fixed it.

    public class PublishedContentRenderModel : IRenderModel
    {
        public PublishedContentRenderModel(IPublishedContent content, CultureInfo culture)
        {
            if(content == null)
            {
                content = new UmbracoHelper(UmbracoContext.Current).TypedContentAtRoot().FirstOrDefault();
                Content = content;
                Culture = culture;
                return;
            }
    
            var baseUrl = HttpContext.Current.Request.Url.AbsoluteUri.Replace(HttpContext.Current.Request.Path, "/");
            var umbUrl = baseUrl + content.Url.TrimStart('/');
    
            var pcr = new PublishedContentRequest(
                new Uri(umbUrl),
                UmbracoContext.Current.RoutingContext,
                UmbracoConfig.For.UmbracoSettings().WebRouting,
                s => Roles.Provider.GetRolesForUser(s)
            );
    
            UmbracoContext.Current.PublishedContentRequest = pcr;
            UmbracoContext.Current.PublishedContentRequest.PublishedContent = content;
    
            pcr.Prepare();
    
            Content = content;
            Culture = culture;
        }
    
        public PublishedContentRenderModel()
            : this(default(IPublishedContent), CultureInfo.CurrentUICulture)
        {
        }
    
        public IPublishedContent Content { get; set; }
    
        public CultureInfo Culture { get; set; }
    }
    
  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies