Walkthrough: Creating a model-bound view that renders a contents resolver
You use contents resolvers with the Sitecore Layout Service to provide more complex data beyond the serialization of a component data source. Common use cases include site navigation, search results, or returning the output or state of custom business logic. In this walkthrough, you learn how to create a contents resolver that returns a model of the content tree for you to render in a model-bound view.
When you have completed the walkthrough, we recommend you familiarize yourself with the Sitecore Helix practices to organize your solution according to the business domain and create a common closure for related code from multiple services. This allows your related content resolvers and rendering code to be co-located within your solution. See the Sitecore Helix Examples repository for inspiration.
To create a contents resolver, you must complete the following procedures:
-
Add the Sitecore.LayoutService NuGet package.
-
Add the Templates class.
-
Create the contents resolver class.
-
Create the contents resolver item.
-
Create the JSON rendering item.
-
Add the JSON rendering item to the standard values of the
AppRoute
template. -
Test the contents resolver.
To create a model-bound view that renders the contents resolver, you must complete the following procedures:
-
Create the model.
-
Create the model-bound view.
-
Register the model-bound view.
-
Test the model-bound view.
Add the Sitecore.LayoutService NuGet package
The Sitecore.LayoutService
NuGet package contains the Sitecore.LayoutService.ItemRendering.ContentsResolvers.RenderingContentsResolver
class that the contents resolver class inherits from.
To add the Sitecore.LayoutService
NuGet package to the Platform
project:
-
In Visual Studio, in Solution Explorer, right-click
Platform/References
and click Manage NuGet Packages. -
In the top-right corner of the window, in the Package source menu, select the package source that points to
https://nuget.sitecore.com/resources/v3/index.json
. -
In the top-left corner of the window, click Browse and search for the
Sitecore.LayoutService
NuGet package. -
In the list of search results, click
Sitecore.LayoutService
. -
On the right side of the window, click Install to download and install the
Sitecore.LayoutService
NuGet package. -
Allow the Nuget Package Manager to modify the solution if required.
Add the Templates class
The Templates
class is a dependency of the contents resolver class.
To add the Templates
class to the Platform
project:
-
In Visual Studio, in Solution Explorer, right-click
Platform
and click Add, New Item. -
In the Add New Item dialog:
-
In the left pane, click
Installed/Visual C#/ASP.NET Core/Code
. -
In the middle pane, click Class.
-
At the bottom, in the Name field, enter
Templates.cs
and click Add.
-
-
In the class file, add the following content:
RequestResponseusing Sitecore.Data; namespace MyProject { public static class Templates { public static class SiteRoot { public static readonly ID Id = ID.Parse("{061CBA15-5474-4B91-8A06-17903B102B82}"); } public static class AppRoute { public static readonly ID Id = ID.Parse("{89829df8-93ee-56be-b57a-8f9efa6ba0a6}"); public static class Fields { public static readonly ID PageTitle = ID.Parse("{09265946-b966-5034-bad7-94e0d935147a}"); } } } }
-
Save the class file.
Create the contents resolver class
The contents resolver class overrides the ResolveContents
method of the Sitecore.LayoutService.ItemRendering.ContentsResolvers.RenderingContentsResolver
class and returns a content tree object.
The ResolveContents
method must return an object that can be returned to the rendering host as a JSON rendering.
To create the contents resolver class in the Platform
project:
-
In Visual Studio, in Solution Explorer, right-click
Platform
and click Add, New Item. -
In the Add New Item window:
-
In the left pane, click
Installed/Visual C#/ASP.NET Core/Code
. -
In the middle pane, click Class.
-
At the bottom, in the Name field, enter
NavigationContentsResolver.cs
and click Add.
-
-
In the class file, enter the following content:
RequestResponseusing System; using System.Collections.Generic; using System.Linq; using System.Web; using Sitecore.Abstractions; using Sitecore.Data.Items; using Sitecore.LayoutService.Configuration; using Sitecore.LayoutService.ItemRendering.ContentsResolvers; using Sitecore.Mvc.Presentation; namespace MyProject.LayoutService { public class NavigationContentsResolver : RenderingContentsResolver { private const int NavigationDepth = 2; private readonly BaseLinkManager _linkManager; public NavigationContentsResolver(BaseLinkManager linkManager) { _linkManager = linkManager; } public override object ResolveContents(Rendering rendering, IRenderingConfiguration renderingConfig) { var contextItem = GetContextItem(rendering, renderingConfig); var siteRoot = contextItem?.Axes.GetAncestors().FirstOrDefault(item => item.DescendsFrom(Templates.SiteRoot.Id)); if (siteRoot == null) { return null; } // First page under our site root should be Home return GetNavigation(siteRoot, NavigationDepth).FirstOrDefault(); } private IEnumerable<object> GetNavigation(Item parent, int depth) { depth--; return parent.Children .Where(item => item.DescendsFrom(Templates.AppRoute.Id)) .Select(item => new { Title = item[Templates.AppRoute.Fields.PageTitle], Url = _linkManager.GetItemUrl(item), Children = depth >= 0 ? GetNavigation(item, depth) : new object[0] }); } } }
-
Save the class file.
-
Right-click the
Platform
project and click Publish. -
In the Platform window, click Publish to publish the
Platform
project in the Sitecore Content Management and Content Delivery instances.
-
Navigation contents resolvers must avoid using
Sitecore.Context.Item
or another page-specific context to output data on current/active navigation items (like highlighting active navigation items in the navigation menu). This is better handled client-side and ensures you can cache navigation data across pages. -
Use Sitecore Content Search instead of Sitecore Query or other resource-expensive methods of navigating the content tree where possible.
Create the contents resolver item
The contents resolver item links the contents resolver class to Sitecore.
To create the contents resolver item in the Sitecore instance:
-
In the Content Editor, right-click
/sitecore/System/Modules/Layout Service/Rendering Contents Resolvers
and click Insert, Rendering Contents Resolver.TipTo optimize serialization, you can organize content resolvers into folders.
-
In the Message dialog, in the Name field, enter
Navigation Resolver
and click OK. -
On the Content tab for the
Navigation Resolver
item, in the Data section, in the Type field, enter the name of the contents resolver:RequestResponseMyProject.LayoutService.NavigationContentsResolver, MyProject
-
Select Use Context Item to make the contents resolver navigate the content tree relative to the current item (the Sitecore context page/route) when building the content tree model. If you do not select this check box, the contents resolver uses its datasource item.
-
Save the contents resolver item.
Create the JSON rendering item
The JSON rendering item renders the output of the contents resolver class (the content tree object) as JSON formatted data for the rendering host.
To create the JSON rendering item in the Sitecore instance:
-
In the Content Editor, right-click
/sitecore/Layout/Renderings
and click Insert, Json Rendering. -
In the Message dialog, in the Name field, enter
Navigation Rendering
and click OK. -
On the Content tab for the
Navigation Rendering
item, in the Layout Service section, in the Rendering Contents Resolver dropdown list, click the Navigation Resolver item. -
Save the JSON rendering item.
If possible, configure output caching for renderings that use content resolvers. This is especially important for renderings that need access to many items, such as navigation.
Add the JSON rendering item to the standard values of the AppRoute template
By adding the JSON rendering item to the AppRoute
templates standard values, all pages that inherit from the AppRoute
template include the JSON rendering.
To add the JSON rendering item to the standard values of AppRoute
templates:
-
In Content Editor, click
/sitecore/Templates/Project/MyProject/AppRoute/__Standard Values
. -
On the Presentation tab, click Details.
-
In the Layout Details dialog, in the Default section, click Edit.
-
In the Device Editor dialog, on the Layout tab, select
Layouts/Project/MyProject/Main
. -
On the Controls tab, click Add.
-
In the Select a Rendering dialog, click
Renderings/Navigation Rendering
. -
In the Add to Placeholder field, click
Main
and click Select. -
In the Device Editor dialog, click OK.
-
In the Layout Details dialog, click OK.
Test the contents resolver
Before starting on the model-bound view, test that the Sitecore Layout Service includes the contents resolver JSON rendering in its output to the rendering host.
Depending on your Rendering Engine configuration, the rendering host page might output an Unknown component
or a similar message. This is perfectly normal.
In this sample JSON rendering, we have added some items to the content tree to populate the navigation model:
{
"uid":"19ea6f2e-3ab9-4e9d-b3a6-9a0e5a6e9d0a",
"componentName":"Navigation Rendering",
"dataSource":"",
"params":{},
"fields":{
"title":"Welcome to Sitecore",
"url":"/en/",
"children":[
{
"title":"Main Nav 1",
"url":"/en/MainNav1",
"children":[
{
"title":"Child Nav 1",
"url":"/en/MainNav1/ChildNav1",
"children":[]
},
{
"title":"Child Nav 2",
"url":"/en/MainNav1/ChildNav2",
"children":[]
}
]
},
{
"title":"Main Nav 2",
"url":"/en/MainNav2",
"children":[
{
"title":"More Child Nav",
"url":"/en/MainNav2/MoreChildNav",
"children":[]
}
]
},
{
"title":"Main Nav 3",
"url":"/en/MainNav3",
"children":[]
}
]
}
}
Create the model
The model provides a strongly typed class that maps to the data in the contents resolver JSON rendering returned by the Sitecore Layout Service.
To create the model in the RenderingHost
project:
-
In Visual Studio, in Solution Explorer, right-click
RenderingHost/Models
and click Add, New Item. -
In the Add New Item window:
-
In the left pane, click
Installed/Visual C#/ASP.NET Core/Code
. -
In the middle pane, click Class.
-
At the bottom, in the Name field, enter
NavigationModel.cs
. -
Click Add.
-
-
In the class file, to bind the JSON rendering to the model, add the following content:
RequestResponseusing System.Collections.Generic; using Sitecore.AspNet.RenderingEngine.Binding.Attributes; namespace MyProject.Models { public class NavigationModel { [SitecoreComponentField] public string Title { get; set; } [SitecoreComponentField] public string Url { get; set; } [SitecoreComponentField] public IEnumerable<NavigationModel> Children { get; set; } } }
NoteBecause you are not binding directly to Sitecore fields, you can use simple types like
string
in your model, but you must explicitly attribute them with[SitecoreComponentField]
. -
Save the class file.
Create the model-bound view
The model-bound view renders the model data as HTML.
To create the model-bound view in the RenderingHost
project:
-
In Visual Studio, in Solution Explorer, right-click
RenderingHost/Views/Shared/Components/SitecoreComponent
and click Add, New Item. -
In the Add New Item window:
-
In the left pane, click
Installed/Visual C#/ASP.NET Core/Web
. -
In the middle pane, click Razor View.
-
At the bottom, in the Name field, enter
Navigation Rendering.cshtml
.ImportantYou get an
Unknown Component
error if the name of the model-bound view file does not match the name of the JSON rendering. -
Click Add.
-
-
In the model-bound view file, add the following content:
RequestResponse@model NavigationModel <ul> <li><a href="@Model.Url">Home</a></li> @foreach (var navigation in Model.Children) { <li> <a href="@navigation.Url">@navigation.Title</a> @if (@navigation.Children != null) { <ul> @foreach (var childNav in navigation.Children) { <li><a href="@childNav.Url">@childNav.Title</a></li> } </ul> } </li> } </ul>
-
Save the model-bound view file.
Register the model-bound view
You must map the model-bound view to the layout service component name (both are called Navigation Rendering
) in the Sitecore Rendering Engine.
To register the model-bound view in the Startup
class:
-
In Visual Studio, in Solution Explorer, double-click the
Startup.cs
file. -
In the
Startup.cs
file, in theservices.AddSitecoreRenderingEngine
call, register the model-bound view and the model as a Rendering Engine component with theAddModelBoundView()
method:RequestResponseservices.AddSitecoreRenderingEngine(options => { //Register your components here options .AddModelBoundView<ContentBlockModel>("ContentBlock") .AddModelBoundView<NavigationModel>("Navigation Rendering") .AddDefaultPartialView("_ComponentNotFound"); }) // Includes forwarding of Scheme as X-Forwarded-Proto to the Layout Service so that // Sitecore Media and other links have the correct scheme. .ForwardHeaders() // Enable forwarding relevant headers and client IP for Sitecore Tracking and Personalization. .WithTracking() // Enable support for the Experience Editor. .WithExperienceEditor(options => { // Experience Editor integration needs to know the external URL of your rendering host, // if behind HTTPS termination or another proxy (like Traefik). if (Configuration.RenderingHostUri != null) { options.ApplicationUrl = Configuration.RenderingHostUri; } });
ImportantYou get an
Unknown Component
error if the name of the model-bound view file does not match the name of the JSON rendering. -
Save the
Startup.cs
file.