13 Oct 2021
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") && x.Value<string>("legacyUrl") == path); } } }
I hope it helps you, and more importantly me when I need the code in 6 months time