Skip to content

Instantly share code, notes, and snippets.

@sotirisf
Last active May 24, 2020 16:49
Show Gist options
  • Select an option

  • Save sotirisf/a8d83e8fca45887cfb3ccc73860526f8 to your computer and use it in GitHub Desktop.

Select an option

Save sotirisf/a8d83e8fca45887cfb3ccc73860526f8 to your computer and use it in GitHub Desktop.
Umbraco Poor Man's Old Url Redirector
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Web;
using Umbraco.Web.PublishedModels;
using Umbraco.Web.Routing;
namespace Site.Core
{
public class OldUrlContentFinder : IContentFinder
{
public virtual bool TryFindContent(PublishedRequest contentRequest)
{
//Get the ORIGINAL request (before cleaning up)
//We actually need the original request, since this is what we're going to redirect from.
//After cleanup url changes e.g. test.aspx?a=1 becomes test?a=1.
var req = contentRequest.UmbracoContext.HttpContext.Request;
var oldUrl = req.ServerVariables["HTTP_HOST"] + req.RawUrl; //Could use Uri.Authority too
var nodesWithRedirects =
(IEnumerable<string[]>)Current.AppCaches.RuntimeCache.GetCacheItem("cachedoldurls", () =>
contentRequest
.UmbracoContext
.Content
.GetAtRoot()
.Where(x => x.TemplateId > 0)
.SelectMany(x => x.Descendants<IAbstractPage>())
.Where(x => x.HasProperty("oldUrl") && !string.IsNullOrEmpty(x.Value<string>("oldUrl")))
.Select(x => new string[] { x.Value<string>("oldUrl"), x.Url })
);
string[] actualNodeEntry = nodesWithRedirects
.Where(x => x[0].UrlEquals(oldUrl))
.FirstOrDefault();
string actualUrl = actualNodeEntry?[1];
if (actualUrl != null)
{
contentRequest.SetRedirectPermanent(actualUrl);
return true;
}
return false;
}
}
public static class UrlUtils
{
public static bool UrlEquals(this string oldUrl, string currentUrl)
{
//Get rid of protocol, since our new url hasn't got one, we're going to compare
//urls without it.
Uri oldUrlUri = new Uri(oldUrl.Replace("https://", "").Replace("http://", ""));
Uri currentUrlUri = new Uri(currentUrl);
UriBuilder ub1 = new UriBuilder(oldUrlUri);
ub1.Query = string.Join("&", oldUrlUri.Query.Replace("?", "").Split('&').OrderBy(x => x));
UriBuilder ub2 = new UriBuilder(currentUrlUri);
ub2.Query = string.Join("&", currentUrlUri.Query.Replace("?", "").Split('&').OrderBy(x => x));
return Uri.Compare(ub1.Uri, ub2.Uri, UriComponents.AbsoluteUri, UriFormat.UriEscaped, StringComparison.InvariantCultureIgnoreCase) == 0;
}
}
}
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Web;
using Umbraco.Web.Routing;
namespace Site.Core
{
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class OldUrlContentFinderComposer : IUserComposer
{
public void Compose(Composition composition)
{
composition.ContentFinders().InsertBefore<ContentFinderByUrl, OldUrlContentFinder>();
}
}
}
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
using Umbraco.Web.PublishedModels;
namespace Site.Core
{
public class SiteEvents : IUserComposer
{
public void Compose(Composition composition)
{
composition.Components().Append<SubscribeToEvents>();
}
}
public class SubscribeToEvents : IComponent
{
private readonly IContentTypeService _contentTypeService;
private readonly ISqlContext _sqlContext;
private readonly IContentService _contentService;
public SubscribeToEvents(IContentTypeService contentTypeService, IContentService contentService, ISqlContext sqlContext)
{
_contentTypeService = contentTypeService;
_contentService = contentService;
_sqlContext = sqlContext;
}
public void Initialize()
{
ContentService.Published += ContentService_Published;
ContentService.Deleted += ContentService_Deleted;
ContentService.Copied += ContentService_Copied;
ContentService.Moved += ContentService_Moved;
ContentService.RolledBack += ContentService_RolledBack;
ContentService.Saved += ContentService_Saved;
ContentService.Publishing += ContentService_Publishing;
ContentService.Unpublished += ContentService_UnPublished;
ClearRuntimeCache();
}
public void Terminate()
{
}
private void ContentService_UnPublished(IContentService sender, PublishEventArgs<IContent> e)
{
ClearRuntimeCache();
}
private void ContentService_Publishing(IContentService sender, ContentPublishingEventArgs e)
{
ClearRuntimeCache();
}
private void ContentService_Saved(IContentService sender, ContentSavedEventArgs e)
{
ClearRuntimeCache();
}
private void ContentService_RolledBack(IContentService sender, RollbackEventArgs<IContent> e)
{
ClearRuntimeCache();
}
private void ContentService_Moved(IContentService sender, MoveEventArgs<IContent> e)
{
ClearRuntimeCache();
}
private void ContentService_Copied(IContentService sender, CopyEventArgs<IContent> e)
{
ClearRuntimeCache();
}
private void ContentService_Deleted(IContentService sender, DeleteEventArgs<IContent> e)
{
ClearRuntimeCache();
}
private void ContentService_Published(IContentService sender, PublishEventArgs<IContent> e)
{
ClearRuntimeCache();
}
private void ClearRuntimeCache()
{
Current.AppCaches.RuntimeCache.ClearByKey("cachedoldurls");
//Add any other stuff you need to do here
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment