Copied to clipboard

Flag this post as spam?

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


  • Bart van der Drift 8 posts 88 karma points
    Aug 29, 2018 @ 12:43
    Bart van der Drift
    0

    Donut hole for Html.Partial

    I am using MvcDonutCaching and Redis cache to cache the output of my web pages. This is working fine, but I wish to add a donut hole for a document type, because there are some random elements in it that should be different on each render.

    The page is looping through its children as follows:

      @foreach (var page in Model.Content.Children.Where(x => x.IsVisible())
      {
        Html.Partial(page.DocumentTypeAlias, page);
      }
    

    I know I can create a donut hole by using Html.Action instead of Html.Partial, but all the examples I can find use static document type names to render the partial in the action, e.g.:

    [ChildActionOnly]
    public ActionResult BlogPosts() {
        // ...
        return PartialView("BlogPosts", posts)
    }
    

    I need to find a way to pass the document type and IPublishedContent to the action. Anyone has any suggestions?

  • Matthew Wise 271 posts 1373 karma points MVP 5x c-trib
    Aug 29, 2018 @ 13:13
    Matthew Wise
    0

    Hi Bart,

    You can do this by create an action that takes in the document type alias and renders the partial view.

    If you need more than just removing it from the cache like BlogPosts in your example then I would use a switch on the Alias and if its BlogPosts call that specific action.

    Matt

  • Bart van der Drift 8 posts 88 karma points
    Aug 29, 2018 @ 13:34
    Bart van der Drift
    0

    Thanks for you response, Matt!

    I now have the following:

    @foreach (var page in Model.Content.Children.Where(x => x.IsVisible())
    {
        if (page.DocumentTypeAlias == "imageGrid")
        {
            @Html.Action("RenderImageGrid", "DefaultTypeController", page, true);
        }
        else
        {
            @Html.Partial(page.DocumentTypeAlias, page);
        }
    }
    

    And the controller contains this action:

        [ChildActionOnly]
        public PartialViewResult RenderImageGrid(IPublishedContent page)
        {
            return PartialView(page.DocumentTypeAlias, page);
        }
    

    However, rendering the page gives me the following exception:

    Type 'Umbraco.Core.Models.IPublishedContent[]' with data contract name 'ArrayOfanyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.

    Any idea on how to continue?

  • Matthew Wise 271 posts 1373 karma points MVP 5x c-trib
    Aug 29, 2018 @ 13:44
    Matthew Wise
    1

    Only way I know how to fix that is pass a simple object through like the page Id and then get the IPublishedContent again in the controller.

    Matt

  • Dave Woestenborghs 3504 posts 12135 karma points MVP 9x admin c-trib
    Aug 29, 2018 @ 13:49
    Dave Woestenborghs
    0

    What Matthew says.

    Just pass the item id into the controller and use the API to get it.

    The problem is because IPublishedContent is not serializable. And under the hood DonutCaching builds a cache key for your partial based on the parameters sent to the action by serializing them

    Dave

  • Bart van der Drift 8 posts 88 karma points
    Aug 29, 2018 @ 13:49
    Bart van der Drift
    0

    Thanks Matt, I've tried this:

        if (page.DocumentTypeAlias == "imageGrid")
        {
            @Html.Action("RenderImageGrid", "ImageGridController", page.Id, true);
        }
    

    And action:

        [ChildActionOnly]
        public PartialViewResult RenderImageGrid(int pageId)
        {
            var umbracoHelper = new UmbracoHelper();
            var page = umbracoHelper.TypedContent(pageId);
            return PartialView(page.DocumentTypeAlias, page);
        }
    

    Now I get the following exception:

    No route in the route table matches the supplied values.

    I hope you can help me further...

  • Dave Woestenborghs 3504 posts 12135 karma points MVP 9x admin c-trib
    Aug 29, 2018 @ 13:51
    Dave Woestenborghs
    1

    Hi Bart,

    I think this line is the problem :

    @Html.Action("RenderImageGrid", "ImageGridController", page.Id, true);
    

    I think you need to omit the Controller suffix,

    So it becomes this ;

    @Html.Action("RenderImageGrid", "ImageGrid", page.Id, true);
    

    Dave

  • Bart van der Drift 8 posts 88 karma points
    Aug 29, 2018 @ 13:54
    Bart van der Drift
    0

    Thanks for the suggestion Dave, but that doesn't work either. The error is the same as before:

    No route in the route table matches the supplied values.

  • Dave Woestenborghs 3504 posts 12135 karma points MVP 9x admin c-trib
    Aug 29, 2018 @ 13:56
    Dave Woestenborghs
    0

    What class does your controller inherit from ?

    Dave

  • Bart van der Drift 8 posts 88 karma points
    Aug 29, 2018 @ 13:57
    Bart van der Drift
    0

    It inherits from Umbraco.Web.Mvc.RenderMvcController

  • Dave Woestenborghs 3504 posts 12135 karma points MVP 9x admin c-trib
    Aug 29, 2018 @ 14:01
    Dave Woestenborghs
    100

    That is the problem. Action on these RenderMvcController don't get auto routed.

    You better off inheriting from SurfaceController (if you don't use route hijacking). If you do use route hijacking than you need to create a seperate controller inheriting from SurfaceController. that one get's auto routed.

    More info can be found here : https://our.umbraco.com/documentation/Reference/Routing/

    Dave

  • Bart van der Drift 8 posts 88 karma points
    Aug 29, 2018 @ 14:33
    Bart van der Drift
    0

    Thank you Dave!!! It's working now. This is how I'm finally calling the action:

    @foreach (var page in Model.Content.Children.Where(x => x.IsVisible())
    {
        if (page.DocumentTypeAlias == "imageGrid")
        {
            @Html.Action("RenderImageGrid", "ImageGrid", new { pageId = page.Id }, true);
        }
        else
        {
            @Html.Partial(page.DocumentTypeAlias, page);
        }
    }
    

    And this is the controller class:

    public class ImageGridController : SurfaceController
    {
        [ChildActionOnly]
        public PartialViewResult RenderImageGrid(int pageId)
        {
            var umbracoHelper = new UmbracoHelper(UmbracoContext);
            var page = umbracoHelper.TypedContent(pageId);
            return PartialView(page.DocumentTypeAlias, page);
        }
    }
    
  • Dave Woestenborghs 3504 posts 12135 karma points MVP 9x admin c-trib
    Aug 29, 2018 @ 14:36
    Dave Woestenborghs
    1

    Cool nice to see you got it working.

    Don't forget to mark the topic as solved.

    Dave

Please Sign in or register to post replies

Write your reply to:

Draft