Migrating the Sitecore MVP site to XM Cloud – Part 1

Thursday, November 24, 2022

Migrating the Sitecore MVP site to XM Cloud

The Developer Advocacy team here at Sitecore recently completed a project to migrate the existing Sitecore MVP site, built with Sitecore XM 10.2, to XM Cloud. Now the original site was built headlessly using the ASP.NET Rendering SDK for the application, and content serialisation was handled using Sitecore Content Serialisation. The fact that both technologies are supported in XM Cloud made our migration much simpler. Now that won’t be the case for many Sitecore customers who have built against earlier versions or haven’t built their site using one of our headless SDKs. The point of this blog series is to cover how the migration process went and highlight a couple of tasks we needed to complete in the process that other people might run into. This will be split into the following four posts; this is the first in the series covering some of the initial changes we undertook as part of the migration. This will then be followed by:

.NET 6 upgrade

The MVP site was originally built using v19 of the ASP.NET Core Rendering SDK, and since then v20 of the SDK had been released, which was built with .NET 6. So upgrading to the latest version meant we could leverage the new features that were released with .NET 6, you can learn all about what’s new in Microsofts release blog. One of the nice things that this let us leverage was the Minimal API functionality. This lets you reduce the amount of code used to bootstrap an application. You can see this comparing the two versions of our Program.cs

Original Version

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace Mvp.Project.MvpSite.Rendering
    public class Program
        public static void Main(string[] args)

        public static IHostBuilder CreateHostBuilder(string[] args) =>
                .ConfigureWebHostDefaults(webBuilder =>

New Version.

using Microsoft.AspNetCore.Builder;
using Mvp.Project.MvpSite.Rendering;

var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);

var app = builder.Build();
startup.Configure(app, app.Environment);

Much cleaner!

HTTPRequestHandler vs GraphQLHander

The next change we had to make was around how the head requested its data from Sitecore. The original version of the MVP site was built from the Getting Started Template. This is a great place to start out when you looking to begin working with the ASP.NET Core Rendering SDK. It is built by default to connect to the LayoutService, however, with XM Cloud we’re going to be running against Sitecore Experience Edge instead.

When we first connected the site to Edge, we noticed that our queries were failing. That was because we needed to change the RequestHandler. When you start a project, it will be provisioned to use the HTTPRequestHandler, if you look in the Startup.cs in the previous repo, you will see the following lines:

    // Set default parameters for the Layout Service Client from our bound configuration object.
    .WithDefaultRequestOptions(request =>
    .AddHttpHandler("default", Configuration.LayoutServiceUri)

This won’t work with Experience Edge as it’s using a GraphQL endpoint instead, so we need to change this configuration to a new GraphQLHander that was introduced in v20 of the SDK. So if you check out the Startup.cs in the new repo, you will see that those lines have now changed to:

// Register the GraphQL version of the Sitecore Layout Service Client for use against experience edge & local edge endpoint
    .AddGraphQlHandler("default", Configuration.DefaultSiteName, Configuration.ExperienceEdgeToken, Configuration.LayoutServiceUri)

Much simpler than the previous implementation. There is also a preview GraphQL endpoint included in the CM application, so you don’t have to switch which provider you’re using for local development, that will work the same for both local and live published data.

One thing to note is that the path in the URL for the production Edge endpoint and the CM preview endpoints are different. For local development, you’ll want to use /sitecore/api/graph/edge whereas when working against Edge the path to use is /api/graphql/v1.

So that brings us to the end of the first post in this series. Next up I’ll be talking about Custom Content Resolvers and how Experience Edge changed how we worked with them.