In this tutorial, you will learn how to generate a Sitemap.xml file within Umbraco v9 powered website. Ensuring all your pages are referenced from a Sitemap.xml file will ensure search engines can successfully index all of your site's content. To create a valid sitemap.xml file it will need to adhere to the sitemap schema. You can learn more about the Sitemap.xml schema and what it should contain here. Today's mission is to generate an XML file that is formatted in accordance with this schema and populated with all the contents added within the Umbraco backend. If you want to learn how to create a badass sitemap, this is the tutorial for you πŸ”₯πŸ”₯πŸ”₯

How To Build A Sitemap.xml Within Umbraco v9

In order to create a sitemap.xml within Umbraco, the first thing you will need to build is a controller. When it comes to building a sitemap, a lot of the Umbraco tutorials recommend starting off by building a sitemap document-type within the Umbraco backend, I do not recommend this. My general approach to content modelling is that if you always need to render a page and that page does not need to be content editable, it does not need to live within the CMS itself. Instead, I prefer generating my sitemap using a vanilla MVC controller. Using a vanilla MVC controller will ensure that a content editor does not accidentally delete the sitemap from within the CMS (this has happened to me before 😞))

Assuming that you are on-board with this architecture choice, the first step is to create the controller:

I like to structure my controllers so the actions are simple and all the custom logic I need to make is added within a service that I use dependency injection to access. The benefit of this architecture is the ability to access that logic from more than one place. The second benefit is that it will allow you to test your codebase more easily 😊

As we are using a vanilla MVC controller, you will need to create a rule within the routing table. This is a standard Umbraco requirement for every vanilla controller. If you do not do this, if you try to access the controller you will encounter a 404 error. The nicest way to add a routing rule is via an extension, like this:

You then register this rule from within the Start class. You can call it like this:

Getting The Umbraco Content: This is the service that I built to query the CMS to return the data required to populate the sitemap:

If you are new to Umbraco v9 and ASP.NET 5, the most interesting thing of note is the use of IHttpContextAccessor. The way we can access the HttpContext has changed within .NET Core compared to ASP.NET Framework. Accessing the context via HttpContxt.Current is no longer a thing. Instead, you can access the current context using IHttpContextAccessor. The reason why I need access to the context is to change the response type. To return an XML file you need to change the contenttype to text/xml. I do this logic within the view, so I pass the context down as a property within the view model. You could add the code to switch the request type in the controller, however, as you will see I like generating the XML structure in my view for simplicity. This is probably one of the only situations where I would add logic into a view. If you do not agree, do what makes you happy ❀️

Creating a sitemap is easy enough, you need to access the homepage object and then get all the pages underneath it. You can get these items by using the .Descendants() extension method on the homepage object. The first step in this process is to access the homepage object. You can do that with this code:

GetByRoute() will return a corresponding Umbraco node based on a URL. As the homepage will always be /, you can use this approach on any site to easily access the homepageπŸ’₯

This file uses two view models, that I will include next:

Depending on the number of pages within your site, the call to generate the sitemap might be very expensive. I will not do a deep dive into caching within this tutorial, however, that does not mean you should not think about caching. You should definitely cache this controller . I tend to put a 24-hour cache on my sitemap controller. The basic code you need to add to enable caching on a controller is shown below:

The last thing to say about this service is registration. I created a custom interface class to go with the service. In order to inject the service into the controller and to allow the dependency injection framework to do its thang, you need to register the service with Umbraco. This can be done using this a composer:

Generating the XML file: For simplicity, I create the entirety of the XML file in the view layer. From personal experience, I find it much easier to change and debug XML files within a view compared to trying to format the document correctly using code within a controller. If you disagree, the good news for you is that it is definitely possible to return an XML file within a controller. The code to do that would look like this:

If you follow this path and it takes you ages to get it working... I told you so πŸ˜‰

To generate the XML structure from within the view, create a corresponding view for the controller. You will need to create a cshtml file within the View folder. Create a folder called XmlSitemap and in here create a new view called Index.cshtml. Within Index.cshtml add this code:

The most important part of this code is on Line 11. Here the code changes the request type. The ContentType property is set to text/xml. If you do not do this, the request will be returned as HTML and the file will not be valid. At the top of the document, you also need to set the XML header. This is done on Line2, by ensuring the below XML is the first line of the document:

After that set-up code is done, the last part is writing the contents of the file and ensuring that it meets the Sitemap schema. You can test this out using the XML Sitemap Validator, here

Happy Coding 🀘