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:
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.:
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.
[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.
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
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.
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.
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);
}
}
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:
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.:
I need to find a way to pass the document type and IPublishedContent to the action. Anyone has any suggestions?
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
Thanks for you response, Matt!
I now have the following:
And the controller contains this action:
However, rendering the page gives me the following exception:
Any idea on how to continue?
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
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
Thanks Matt, I've tried this:
And action:
Now I get the following exception:
I hope you can help me further...
Hi Bart,
I think this line is the problem :
I think you need to omit the Controller suffix,
So it becomes this ;
Dave
Thanks for the suggestion Dave, but that doesn't work either. The error is the same as before:
What class does your controller inherit from ?
Dave
It inherits from Umbraco.Web.Mvc.RenderMvcController
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
Thank you Dave!!! It's working now. This is how I'm finally calling the action:
And this is the controller class:
Cool nice to see you got it working.
Don't forget to mark the topic as solved.
Dave
is working on a reply...