[ACCEPTED]-MVC: How to route /sitemap.xml to an ActionResult?-sitemap.xml

Accepted answer
Score: 22

Add a map for:

routes.MapRoute(
            "Sitemap",
            "sitemap.xml",
            new { controller = "Home", action = "SiteMap" }
            );

Notice that the route, controller, and 1 action options are hard coded.

Score: 9

You can used this.

Step 1. Mapping the file extension to TransferRequestHandler

IIS 7 Integrated mode 42 uses HTTP Handler mappings which point path 41 / verb combinations to an HTTP Handler. For 40 example, there's a default handler mapping 39 which points path="*.axd" verb="GET,HEAD,POST,DEBUG" to 38 the appropriate ISAPI module for the .NET 37 runtime version the site's running under. The 36 easiest way to see the default handlers 35 under IIS Express is to run a site under 34 IIS Express, right-click the IIS Express 33 icon in the system tray, click "show all 32 applications", and click on a site. The 31 applicationhost.config link at the bottom 30 is linked, so you can just click on it and 29 it should load in Visual Studio.

If you scroll 28 to the bottom, you'll see that there's a 27 catchall StaticFile mapping for path="*" verb="*" which points 26 to StaticFileModule,DefaultDocumentModule,DirectoryListingModule. That's what will handle your .html 25 request if you do nothing. So the first 24 step is to add a handler in your web.config 23 that will point *.html requests to the TransferRequestHandler. TransferRequestHandler is the 22 handler that takes care of the extensionless 21 URLs you're used to seeing in MVC routes, e.g. /store/details/5.

Adding 20 a handler mapping is really easy - just 19 open up your web.config and add it to the 18 <system.webServer/handlers> node.

<add name="HtmlFileHandler" path="*.html" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

Note that you can make the path more 17 specific if you'd like. For instance, if 16 you only wanted to intercept one specific 15 request, you could use path="sample.html"

Step 2. Configuring the route

Next, you'll 14 need a new route. Open up App_Start/RouteConfig.cs and it to the 13 RegisterRoutes call. My complete RegisterRoutes looks like this:

  routes.MapRoute(
       name: "XMLPath",
       url: "sitemapindex.xml",
       defaults: new { controller = "Home", action = "Html", page = UrlParameter.Optional }
   );

Step 3. Route Existing Files

That 12 almost covers it, but there's one more thing 11 to take care of - overriding requests that 10 match an existing file. If you've got an 9 actual file called myfile.html, the routing 8 system won't allow your route to run. I 7 forgot about this, ended up with an HTTP 6 500 error (recursion overflow) and had to 5 ask Eilon Lipton for help.

Anyways, that's 4 easy to fix - just add routes.RouteExistingFiles 3 = true to your route registration. My completed 2 RegisterRoutes call looks like this:

public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.RouteExistingFiles = true;

        routes.MapRoute(
            name: "CrazyPants",
            url: "{page}.html",
            defaults: new { controller = "Home", action = "Html", page = UrlParameter.Optional }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
    }

That's 1 it.

I tested by adding this controller action:

public FileResult Html()
{
    var stringBuilder = new StringBuilder();
    stringBuilder.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
    stringBuilder.AppendLine("<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">");
    stringBuilder.AppendLine("<sitemap>");
    stringBuilder.AppendLine("<loc>http://sprint-newhomes.move.com/sitemaps/sitemap_01.xml</loc>");
    stringBuilder.AppendLine("<lastmod>" + DateTime.Now.ToString("MMMM-dd-yyyy HH:mm:ss tt") + "</lastmod>");
    stringBuilder.AppendLine("</sitemap>");
    stringBuilder.AppendLine("<sitemap>");
    stringBuilder.AppendLine("<loc>http://sprint-newhomes.move.com/sitemaps/sitemap_02.xml</loc>");
    stringBuilder.AppendLine("<lastmod>" + DateTime.Now.ToString("MMMM-dd-yyyy HH:mm:ss tt") + "</lastmod>");
    stringBuilder.AppendLine("</sitemap>");
    stringBuilder.AppendLine("</sitemapindex>");

    var ms = new MemoryStream(Encoding.ASCII.GetBytes(stringBuilder.ToString()));



    Response.AppendHeader("Content-Disposition", "inline;filename=sitemapindex.xml");
    return new FileStreamResult(ms, "text/xml");
}
Score: 8

To get this to work you need to do 2 things:

  1. Instruct the IIS to allow the static file request "/sitemap.xml" to hit your controller. Otherwise the IIS will bypass your application and look directly for a file with this name. Add the following line to your web.config:
<system.webServer>
    <handlers>

        <!-- add the following line -->
        <add name="SitemapXml" path="sitemap.xml" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/>

    </handlers>
</system.webServer>
  1. Place a route in your MVC application that matches this request to an ActionResult (make sure you place it before your default route):
routes.MapRoute(
    name: "Sitemap",
    url: "sitemap.xml",
    defaults: new { controller = "YourControllerName", action = "YourActionName" }
);

0

More Related questions