Sitecore MVC Rendering Datasources
Today I got a report of a bug with a rendering on a product page of our site. I checked the usual suspects; are there any broken links in the item? is it published? is everything referenced by this page published? None of the above.
It turned out that someone had set a datasource on a container rendering causing child renderings to use that datasource instead of the page item. Setting a datasource on a rendering with no fields would not matter in regular Sitecore, however in Sitecore MVC this changes the rendering context for child renderings. In this case the renderings within the placeholders of the container rendering broke as they were now attempting to render data from a different type of item.
The root of the problem (rogue users aside) was that the controller used
RenderingContext.Current.Rendering.Item assuming that the rendering (and the container rendering) would never have a datasource set and would thus get their data from the page item. This is the most flexible approach if you have a component which potentially could use the page item or a datasource item. The solution was to instead use
RenderingContext.Current.PageContext.Item which always references the page item irrespective of the datasource value or that of any parent renderings.
How to get a Sitecore MVC rendering datasource
There are three ways in Sitecore MVC to access a datasource/context item for a rendering all available from
The datasource of the current rendering, or the datasource of an ancestor rendering if specified, or the page item if no datasource set and no ancestor rendering with datasource. Rendering datasource takes priority.
- Ideal for components e.g. sidebar items where the datasource is a separate item from the page.
- Flexible. Allows rendering to fall back to context item (page or parent rendering) if datasource is empty.
The the current page item, or the datasource of the ancestor rendering.
- Ignores rendering datasource.
- References the page item OR, if set, the datasource of an ancestor rendering.
- Enables you to swap datasources of several renderings at once within a page.
- Less commonly needed.
The page item (equivalent to writing Sitecore.Context.Item in WebForms)
- Ignores datasource set on rendering.
- Ignores datasource of any ancestor renderings.
In short, for Sitecore MVC renderings which render content of the current page use:
For renderings which have a datasource set to a different item than the current page, use:
I have made a simple solution to demonstrate these three ways of passing context to a rendering: https://github.com/dresser/SitecoreMvcRenderingDataSources.
(Uses Sitecore 8.0 rev. 150812)
Container Rendering: a rendering which does not display any content from Sitecore and serves only to render HTML markup and define placeholders for other renderings.
Edit: July 2016
Kamruz Jaman mentioned to me the
Mvc.AllowDataSourceNesting setting which controls how
RenderingContext.Current.ContextItem behaves. The setting can be found in
This is the default behaviour described in this article. When true, the ContextItem property can return the datasource item of the parent rendering if the datasource of the current rendering is not set.
When false, the ContextItem either renders the datasource of the current rendering (if set), or the context item of the page.
As usual, I was not the only one to have reported this behaviour. Here are some other related articles: