How to serve content for legacy .html urls in an Umbraco 8 site

Posted written by Paul Seal on October 13, 2021 Umbraco

I needed to do this on a project last year. I meant to share my solution but I forget.

Here is the code if you are looking for it.

using System;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.SessionState;
using CodeShare.Core.Extensions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web;

namespace CodeShare.Core.Handlers
{
    public class HtmlHandler : IHttpHandler, IRequiresSessionState
    {
        public void ProcessRequest(HttpContext context)
        {
            var contextBase = context.ToBase();
            var originalUrl = context.Request.Url.PathAndQuery;

            if (originalUrl.StartsWith("/umbraco"))
            {
                UseExistingStaticFileHandler(context);
                return;
            }

            string path = context.Server.MapPath(context.Request.RawUrl);

            // Is there a file that already exists on the file system?
            // If so, always serve that.
            if (System.IO.File.Exists(path))
            {
                Umbraco.Web.Composing.Current.Logger.Debug<HtmlHandler>("Streaming specified static file from disk.");

                contextBase.Response.TransmitFileContent(path);
                return;
            }

            // Ensure there is an Umbraco context that is necessary for data access.
            var umbracoContextFactory = Umbraco.Web.Composing.Current.Factory.GetInstance(typeof(IUmbracoContextFactory)) as IUmbracoContextFactory;
            var umbracoContext = umbracoContextFactory?.EnsureUmbracoContext(contextBase)?.UmbracoContext;
            if (umbracoContext == null)
            {
                Umbraco.Web.Composing.Current.Logger.Warn<HtmlHandler>("Umbraco context is null even after ensuring there is one!");
                throw new HttpException((int)HttpStatusCode.NotFound, "Page Not Found");
            }


            //use the correct content type alias here for your root node
            var homeNode = umbracoContext.Content.GetAtRoot().FirstOrDefault(x => x.ContentType.Alias == "homePage");

            IPublishedContent content = null;
            if (homeNode != null)
            {
                content = GetContentWithMatchingLegacyUrl(homeNode, path: originalUrl);
            }

            if (content != null)
            {
                context.Response.RedirectPermanent(content.Url);
            }
            else
            {
                UseExistingStaticFileHandler(context);
            }

        }

        private static void UseExistingStaticFileHandler(HttpContext context)
        {
            Type type = typeof(HttpApplication).Assembly.GetType("System.Web.StaticFileHandler", true);
            IHttpHandler handler = (IHttpHandler)Activator.CreateInstance(type, true);
            handler.ProcessRequest(context);
        }

        public bool IsReusable => false;

        private static IPublishedContent GetContentWithMatchingLegacyUrl(IPublishedContent rootNode, string path)
        {
            return rootNode.DescendantsOrSelf().FirstOrDefault(
                x => x.HasValue("legacyUrl") &amp;&amp; x.Value<string>("legacyUrl") == path);
        }
    }
}

I hope it helps you, and more importantly me when I need the code in 6 months time