Skip to main content

Sitecore

.NET Core Renderings for XM Cloud finally gets some love

Net Core Logo

That is not a secret – Sitecore always used to prioritize Next.Js framework as the first-class citizen for XM Cloud. All the best and finest features tend to find their way to a given framework in the first place. However, recently, there has been much activity around the .NET Core Rendering Framework which makes a lot of sense given most of us, Sitecore tech professionals, originate from the Microsoft and .NET background. More excitement – that is done on .NET 8, which is the latest LST runtime!

Starter Kit

ASP.NET Core framework was with us for a while, periodically receiving some minor updates and fixes. But let’s be honest: having an SDK on its own is one thing, but receiving a decent starter kit on top of that framework is what makes us developers actually create at scale. And that moment has just occurred – without any loud fanfare, XMC ASP.NET Core Starter Kit went public. Please be aware that this is only a PRE-RELEASE version and has its own temporal shortcomings, I gave it a try and want to share my findings with you.

What are these shortcomings? Just a few:

  • FEaaS and BYOC components are not yet supported, therefore you also cannot use Form since it leverages those
  • System.Text.Json serializer is more strict than Newtonsoft which was removed in favor of a built-in solution, thus some components may fail
  • SITECORE_EDGE_CONTEXT_ID variable is not supported

Everything else seems to work the same. There are also some expectations of XM Cloud supporting .NET Rendering at a built-in editing host at some time later in the same manner that works today along with JSS applications, but I do not work for Sitecore and can only make assumptions and guesses without any certainty to it.

First Impression

I forked the repo and cloned the forked code into my computer. Let’s take a look at what we have got there.

Vs Code

  • the code varies from what we used to see from XM Cloud Foundation Head starter kit, and that’s understood
  • at the root folder we still have xmcloud.build.json, sitecore.json and folders – .config and .sitecore
  • xmcloud.build.json is required for cloud deploy, but does not have renderingHosts root section required for editing host(s), as I explained above
  • there is headapps folder to keep the solution file along with .NET projects subfolder(s), currently just a single one – aspnet-core-starter
  • there is also local-containers folder that contains docker-compose files, .env, docker files, scripts, Traefik, and the rest of the container assets we got used to
  • another difference – authoring folder contains serialization settings and items as well as .NET framework project for CM customizations
  • however, there are no init.ps1 and up.ps1 files, but that is easy to create yourself by stealing and modifying those from XM Cloud Foundation Head

With that in mind, we can start investigating. There is a ReadMe document explaining how to deploy this codebase, but before going ahead with it I of course decided to:

Run Local Containers

There are no instructions on container setup, only for cloud deployment, but after spending a few years with Foundation Head, the very first thing that naturally comes into my mind is running this starter kit in local Docker containers. Why not?

There are a couple of things one should do first prior to spinning up containers.

  1. Modify settings in .ENV file – at least these two:
# Enter the value for SQL Server admin password:
SQL_SA_PASSWORD=SA_PASSWORD

# Provide a folder storing a Sitecore license file:
HOST_LICENSE_FOLDER=C:\Projects
  1. We need to generate Traefik SSL Certificates. To do so let’s create .\local-containers\init.ps1 script with the below content:
[CmdletBinding(DefaultParameterSetName = "no-arguments")]
Param ()
$ErrorActionPreference = "Stop";

# duplicates in Up.ps1 scrips
$envContent = Get-Content .env -Encoding UTF8
$xmCloudHost = $envContent | Where-Object { $_ -imatch "^CM_HOST=.+" }
$renderingHost = $envContent | Where-Object { $_ -imatch "^RENDERING_HOST=.+" }
$xmCloudHost = $xmCloudHost.Split("=")[1]
$renderingHost = $renderingHost.Split("=")[1]

Push-Location docker\traefik\certs
try {
    $mkcert = ".\mkcert.exe"
    if ($null -ne (Get-Command mkcert.exe -ErrorAction SilentlyContinue)) {
        # mkcert installed in PATH
        $mkcert = "mkcert"
    } elseif (-not (Test-Path $mkcert)) {
        Write-Host "Downloading and installing mkcert certificate tool..." -ForegroundColor Green
        Invoke-WebRequest "https://github.com/FiloSottile/mkcert/releases/download/v1.4.1/mkcert-v1.4.1-windows-amd64.exe" -UseBasicParsing -OutFile mkcert.exe
        if ((Get-FileHash mkcert.exe).Hash -ne "1BE92F598145F61CA67DD9F5C687DFEC17953548D013715FF54067B34D7C3246") {
            Remove-Item mkcert.exe -Force
            throw "Invalid mkcert.exe file"
        }
    }
    Write-Host "Generating Traefik TLS certificate..." -ForegroundColor Green
    & $mkcert -install
    & $mkcert "$xmCloudHost"
    & $mkcert "$renderingHost"
}
catch {
    Write-Error "An error occurred while attempting to generate TLS certificate: $_"
}
finally {
    Pop-Location
}

Write-Host "Adding Windows host"
Add-HostsEntry "$renderingHost"
Add-HostsEntry "$xmCloudHost"

Write-Host "Done!" -ForegroundColor Green

And then execute this script:

Certs

There is no up.ps1 script, so instead let’s run docker-compose directly: docker compose up -d

You may notice some new images show up, and you also see a new container: aspnet-core-starter

Docker

If everything is configured correctly, the script will execute successfully. Run Sitecore from its default hostname, as configured in .env file: https://xmcloudcm.localhost/sitecore

From there you will see no significant changes. Containers just work well! Sitecore has no content to interact with the head application. I will add the content from the template but let’s make the could deployment first.

Deploy to the Cloud

ReadMe document suggests an inconvenient way of cloud deployment:

1. Create a repository from this template. 2. Log into the Sitecore Deploy Portal. 3. Create a new project using the ‘bring your code’ option, and select the repository you created in step 1.

For the majority of us, who are on the Sitecore Partner side, there are only six environments available grouped into two projects. These allocations are priceless and are carefully shared between all XM Cloud enthusiasts and aspirants who are learning a new platform. We cannot simply “create a new project” because we don’t have that spare project, so in order to create one we have to delete the existing one. Deleting a project requires deleting all (three) of its environments in the first place, which is half of the sandbox capacity, carrying valuable work in progress for many individuals.

That is why I decided to use CLI instead. Luckily it works exactly the same as it does with Next.Js starter kits, and from .\.config\dotnet-tools.json you may see that it uses that same version. You deploy the root folder holding xmcloud.build.json file as a working directory, so there are no changes in execution.

Eventually, once deployed we navigate to XM cloud. I decided to follow the ReadMe and create a Basic site from Skate Park template. Basically, I am following steps 4-18 from the ReadMe file.

As a side exercise, you will need to remove a Navigation component from a Header partial item, located at /sitecore/content/Basic/Basic/Presentation/Partial Designs/Header. Basic site will break in the debugger if you do not delete currently incompatible rendering that has a serialization issue.

Building Dev Tunnel in Visual Studio

Next, let’s open and build the solution in the Visual Studio IDE, which refers to .\headapps\aspnet-core-starter.sln file. You may see it related to three Sitecore dependencies from Sitecore.AspNetCore.SDK.LayoutService.Client:

  • Transient: Sitecore.AspNetCore.SDK.LayoutService.Client.Interfaces.ISitecoreLayoutClient
  • Singleton: Sitecore.AspNetCore.SDK.LayoutService.Client.Serialization.ISitecoreLayoutSerialize
  • Singleton: Sitecore.AspNetCore.SDK.LayoutService.Client.Serialization.Converter.IFieldParser

Modify .\headapps\aspnet-core-starter\appsettings.json with the setting values collected from the previous steps. You will end up with something looking as:

Appsettings.json

Now let’s create a Dev Tunnel in VisualStudio:

Dev Tunnel

There will be at least two security prompts:

Dev Tunnel Authorize GithubDev Tunnel Authorize Notice

If everything goes well, a confirmation message pops up:

Dev Tunnel Created

Now you will be able to run and debug your code in Visual Studio:

Debugger Works

Make a note of the dev tunnel URL, so that we can use it to configure Rendering Host, as described at step 27 of ReadMe. You will end up with something as below:

Rendering Hosts

So far so good. You can now run the website by URL and in Experience Editor. Running in Page will however not work yet due to the below error:

No Pages Without Publish

To explain that, Experience Editor runs as a part of CM and pulls content from a GraphQL endpoint on that same CM. Pages instead is a standalone separate application, so it does not have access neither to the endpoint nor to the Rendering Hosts settings item. It only has access to Experience Edge so we must publish first. Make sure you publish the entire Site Collection. Once complete, Page works perfectly well and displays the site:

Pages Work 1 Pages Work 2

To explain what happens above: Pages app (which is a SaaS-run editor) pulls Experience Edge for the settings of the rendering editing host (which runs in a debuggable dev tunnel from Visual Studio) and renders HTML right there with the layout data and content pulled from Experience Edge.

Deploy Rendering Host to Cloud

Without much thinking, I decided to deploy the rendering host as Azure Web App, with the assumption that the .NET 8 application would be best supported in its native cloud.

Web App Configure

After the Web App is created, add the required environmental variables. The modern and shiny SITECORE_EDGE_CONTEXT_ID variable is not yet supported with .NET Core SDK, so we should go the older way:

Azure App Settings

A pleasant bonus of GitHub integration is that Azure creates GitHub Actions workflow with the default functional build and deployment. There is almost nothing to change,  I only made a single fix replacing run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp with a hardcoded path since this variable contains space from “Program Files” part and is incorrectly tokenized breaking the build. After this fix, GitHub actions got built the right way and I started receiving green status:

Github Actions

… and the published site shows up from the Azure Web App powered rendering host:

Published Site

Finally, we can get rid of Dev Tunnel, replacing it with the actual “published site” hostnames:

Getting Rid Of Dev Tunnel

After republishing the Rendering Host item to Edge, we can stop the debugger and close Visual Studio. Both Experience Editor and Pages app are now working with an editing host served by the Azure Web App.

Verdict

Of course, that would be much anticipated for XM Cloud to have built-in .NET editing host capabilities same way as JSS does. But even without it, I applaud to Sitecore development team for making and keeping working on this starter kit as that is a big milestone for all of us within the .NET Community!

With this kit, we can now start building XM Cloud powered .NET app at a faster pace. I believe all the missing features will find their way to the product, and maybe later there will be some (semi)official SSG support for .NET, something like Statiq. That will allow deployments to a wider set of hosting, such as Azure Static Web Apps, Netlify, and even Vercel which does not support .NET as of today.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Martin Miles

Martin is a Sitecore Expert and .NET technical solution architect involved in producing enterprise web and mobile applications, with 20 years of overall commercial development experience. Since 2010 working exclusively with Sitecore as a digital platform. With excellent knowledge of XP, XC, and SaaS / Cloud offerings from Sitecore, he participated in more than 20 successful implementations, producing user-friendly and maintainable systems for clients. Martin is a prolific member of the Sitecore community. He is the author and creator of the Sitecore Link project and one of the best tools for automating Sitecore development and maintenance - Sifon. He is also the founder of the Sitecore Discussion Club and, co-organizer of the Los Angeles Sitecore user group, creator of the Sitecore Telegram channel that has brought the best insight from the Sitecore world since late 2017.

More from this Author

Categories
Follow Us