Generate a sitemap.xml for your Episerver website

In this post, I will cover how you can generate a sitemap.xml for your Episerver website. All credits to Geta SEO Sitemaps, you will now be able to generate one in under 5 minutes!

  1. Download and install the Nuget package “Geta.SEO.Sitemaps” to your Episerver application Geta.SEO.Sitemaps Nuget package
  2. Build and run your application
  3. Navigate to Admin > Tools and you will find the “Search engine sitemap settings”. Fill in the correct details here. You can even add multiple sitemaps if your Episerver instance has multiple sites / languages. Geta SEO Sitemap settings
  4. Enable the scheduled job by going to Admin > Scheduled Jobs. Apply your settings and manually start the job to test and see your sitemap.xml

Easy peasy!  🙂

Uploading a database to Azure using SQL Server Management Studio

Took me a while to find out, but deploying a SQL Server database to Azure is actually very easy. Make sure you have your Azure connection details ready!

The below instructions / screenshots are from SSMS 2016. Should work for older versions too, although you might see different wordings.

  1. Open SQL Server Management Studio (SSMS) and connect to the SQL Server where your local database is hosted
  2. Right Click on the database > Deploy Database to Microsoft Azure SQL Database Deploy Database to Microsoft Azure SQL Database
  3. Specify connection details by clicking on “Connect”. 
  4. After entering details, click on “Options” below, to specify the timeout to be 60 seconds. (Had to do this in my case cos my database is hosted in South Central US and I’m connecting from Australia it kept timing out). I ticked the “Encrypt connection” true too. 
  5. Back to the Deployment settings window > Specify your Microsoft Azure SQL Database settings. Make sure you choose what you need as this affects payment / subscription.
  6. When everything looks good > click next and it will upload your database to Azure for you!


Episerver CMS Content Migration

Content Migration

I will cover how to automate content migration into an Epi website from a non-Epi CMS. Yes, you read that right. You can automate migration of content into Epi from another CMS and save yourselves the time and money required for a manual data-entry.

Even if your content is currently stored in a Java-based CMS, PHP-based CMS, it can be done. As long as you (or your devs) have access to your current non-Epi CMS database and can perform queries to, then it is doable.

If you are a non-technical person who has a technical resource willing to build it for you, then you can stop here and forward this blog entry to them. You’re welcome.

If you are a non-technical person who doesn’t have a technical resource to do it, then PM me on

If you are a technical person, then the below post is for you. High level, here are the steps you need to take:

  1. Prepare the  assets in your file system in the structure you want them to be uploaded in Epi.
  2. Develop a tool that, when given a file path, will read the contents and upload the files programmatically into the Episerver Assets. Tool discussed here.
  3. Create a JSON/XML export file from your current non-Epi CMS
  4. Create an Epi plugin that can understand the JSON/XML export file and use the Episerver API to programmatically create your pages/blocks

The assets migration has to happen first so when you’re ready to migrate content, your pages/blocks can properly refer to the correct existing assets (i.e. using ContentReference properties)

The sample code below uses JSON. The file on step 3 should look something like this:

CMS Content source

What the fourth tool needs to do is recursively parse the JSON file and based on the “Type”, it will create the relevant Episerver page type. Thanks to Episerver API.

The heart of this tool is this recursive method below.

private ContentReference GetOrCreatePage<T>
(JObject jsonPage, ContentReference parentPageReference) 
where T : PageData
   // check if page exists...
   var existingPage = ContentRepository.Service.GetChildren<T>(parentPageReference)
      .FirstOrDefault(c => c.Name == (string)jsonPage["Name"]);

   ContentReference pageReference;
   if (existingPage == null) {
      var newPage = ContentRepository.Service.GetDefault<T>(parentPageReference);
      pageReference = ContentRepository.Service.Save(newPage, SaveAction.SkipValidation);
   } else {
      pageReference = existingPage.ContentLink;

   // Populate content
   PopulateContent(pageReference, jsonPage);

   // Iterate through child pages and recursively get or create
   foreach (var childPage in (JArray)jsonPage["Children"]) {
      GetOrCreatePage((JObject)childPage, pageReference);

   return pageReference;

You will also need helper methods such as getting content reference based on url:

private ContentReference GetContentReferenceForUrl(string url) {
   return UrlResolver.Service.Route(new UrlBuilder(url))?.ContentLink;

I also have a method that takes care of updating/creating a block for a page:

private void UpdateOrCreateBlockForPage<T>(string blockName, JObject jsonBlock, ContentReference parentLink, ContentArea contentArea) 
where T : BlockData {
   // check if block exists on page
   var assetFolder = ContentAssetHelper.Service.GetOrCreateAssetFolder(parentLink);
   var existingBlock = ContentRepository.Service.GetChildren<T>(assetFolderForPage.ContentLink)
      .FirstOrDefault(b => (b as IContent).Name == blockName);

   ContentReference blockReference;
   if (existingBlock == null) {
      var newBlock = ContentRepository.Service.GetDefault<T>(assetFolderForPage.ContentLink);
      (newBlock as IContent).Name = blockName;
      blockReference = ContentRepository.Service.Save(newBlock as IContent, SaveAction.SkipValidation);
      if (contentArea == null) contentArea = new ContentArea();
      contentArea.Items.Add(new ContentAreaItem {
         ContentLink = (existingBlock as IContent).ContentLink
    } else {
      blockReference = existingBlock.ContentLink;

    // update content
    PopulateContentForBlock(blockReference, jsonBlock);


That’s pretty much it. Hope you get the flow!

If you get stuck/have questions, post a comment below or email me on

Appreciate a comment if this has helped you in anyway!