1

How can I serve a dynamic sitemap.xml file from ASP.NET Core 3.1?

I tried something like:

...
public ActionResult SiteMap()
{
    // logic here
    return Content("<sitemap>...</sitemap>", "text/xml");
}
...
John Conde
  • 217,595
  • 99
  • 455
  • 496
Amigo
  • 47
  • 8
  • For situations like this is often nice to have an external process generating the sitemap.xml file once a day and then putting it into the root website folder, that way your code doesn't have to know or care about it. How you crawl / index / manage your sitemap is up to you. – jjxtra Jan 17 '20 at 22:49

1 Answers1

0

Yes, that's exactly the right approach. Of course, assuming you're using the standard sitemap protocol you'll need to:

  1. Establish an XML declaration (e.g., <?xml version="1.0" encoding="UTF-8"?>)
  2. Start with a <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" /> element

So, for example, if you want to assembly your XML using an XDocument, you could start with something like:

private static readonly XNamespace _sitemapNamespace = "http://www.sitemaps.org/schemas/sitemap/0.9";
private static readonly XNamespace _pagemapNamespace = "http://www.google.com/schemas/sitemap-pagemap/1.0";

public ActionResult Sitemap() {
  var xml = new XDocument(
    new XDeclaration("1.0", "utf-8", String.Empty),
    new XElement(_sitemapNamespace + "urlset",
      //Your logic here
    )
  return Content(sitemap.ToString(), "text/xml");
  );
}

That said, with this code, you'll run into an issue with your XML declaration not being returned with your XML, since XDocument.ToString() only returns an XML snippet. To fix this, you need to wrap your XDocument in e.g. a StringWriter:

var sitemapFile = new StringBuilder();
using (var writer = new StringWriter(sitemapFile)) {
  sitemap.Save(writer);
}
return Content(sitemapFile.ToString(), "text/xml");

Note: There are obviously other approaches for dynamically generating your XML. If you're using an XmlWriter or an XmlDocument, your code will look quite different. The point is to help fill out what a real-world implementation might look like, not to prescribe an exclusive approach.

Are there specific problems you're running into with your attempt? If so, I may be able to provide more specific guidance. But, as is, the approach you are taking is correct.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
  • Aside, one of my projects has a [`SitemapController`](https://github.com/OnTopicCMS/OnTopic-Library/blob/master/OnTopic.AspNetCore.Mvc/Controllers/SitemapController.cs) you can reference, if that's useful. That said, the logic is highly specific to our CMS and accounts for a lot of [structured metadata](https://developers.google.com/search/docs/guides/intro-structured-data) that you probably don't care about. Nevertheless, it demonstrates one approach for assembling an `XDocument` dynamically and returning it via `Content(xml, "text/xml")`. – Jeremy Caney Jan 17 '20 at 23:09
  • I get a 404 when i try to call it, im not really sure why. i did try to ad route to it: ... endpoints.MapControllerRoute( name: "Sitemap", pattern: "/{page?}/{id?}", defaults: new { controller = "Home", Action = "Sitemap", language = "da" }); ... – Amigo Jan 17 '20 at 23:13
  • my code looks like this public ActionResult Sitemap() { // logic here StringBuilder sb = new StringBuilder(); sb.Append(""); sb.Append(""); sb.Append(""); sb.Append(">http://www.example.com/"); sb.Append(""); sb.Append(""); return Content(sb.ToString(), "text/xml"); } – Amigo Jan 17 '20 at 23:19
  • 1
    @Amigo: Most likely, your 404 is due to a routing issue, and not a specific error with your `Sitemap()` action. One potential problem with the route you listed above is that it provides a very general `pattern`, which may be getting superseded by another endpoint. Assuming you only intend to have one main sitemap, I'd consider just adding a `[Route("Sitemap")]` attribute to your controller. Alternatively, if you want to maintain a sitemap-specific route, I'd change your pattern to e.g. `Sitemap`. Note that the leading `/` in your current `pattern` might also be causing problems. – Jeremy Caney Jan 17 '20 at 23:45
  • @Amigo: That said, assuming you already have a route setup for your `HomeController`, you probably don't need to configure an explicit route for your `Sitemap` action. Your default route should address this. Of course, in that case, you'll need to use the pattern `{action?}/{id?}` to ensure that `/Sitemap` gets mapped to the `action` route parameter, and thus the `Sitemap()` action of your `HomeController`. – Jeremy Caney Jan 17 '20 at 23:50
  • 1
    cool its working, my route was not correct. i changed pattern to just "sitemap" and all is fine. Thanks a lot for helping Jeremy (y) – Amigo Jan 17 '20 at 23:51