Walkthrough: Creating a model-bound view that renders a contents resolver
If you integrated your ASP.NET Core app before September 2024, it's using the legacy ASP.NET Core Rendering SDK, version 22 or earlier. This SDK is no longer receiving updates, so we recommend that you upgrade to the latest version of the new ASP.NET Core SDK.
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
AppRoutetemplate. -
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/Referencesand 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.LayoutServiceNuGet 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.LayoutServiceNuGet 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
Platformand 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.csand 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
Platformand 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.csand 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
Platformproject and click Publish. -
In the Platform window, click Publish to publish the
Platformproject in the Sitecore Content Management and Content Delivery instances.
-
Navigation contents resolvers must avoid using
Sitecore.Context.Itemor 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 Resolversand 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 Resolverand click OK. -
On the Content tab for the
Navigation Resolveritem, 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/Renderingsand click Insert, Json Rendering. -
In the Message dialog, in the Name field, enter
Navigation Renderingand click OK. -
On the Content tab for the
Navigation Renderingitem, 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
Mainand 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/Modelsand 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
stringin 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/SitecoreComponentand 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 Componenterror 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.csfile. -
In the
Startup.csfile, in theservices.AddSitecoreRenderingEnginecall, 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 Componenterror if the name of the model-bound view file does not match the name of the JSON rendering. -
Save the
Startup.csfile.