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; }
    }
    
Please Sign in or register to post replies

Write your reply to:

Draft