diff --git a/src/Umbraco.Web/Routing/RedirectTrackingEventHandler.cs b/src/Umbraco.Web/Routing/RedirectTrackingEventHandler.cs
index 65cad094dc..65aac4658d 100644
--- a/src/Umbraco.Web/Routing/RedirectTrackingEventHandler.cs
+++ b/src/Umbraco.Web/Routing/RedirectTrackingEventHandler.cs
@@ -9,6 +9,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Publishing;
using Umbraco.Core.Services;
+using Umbraco.Core.Strings;
using Umbraco.Core.Sync;
using Umbraco.Web.Cache;
using Umbraco.Web.PublishedCache;
@@ -25,9 +26,10 @@ namespace Umbraco.Web.Routing
///
public class RedirectTrackingEventHandler : ApplicationEventHandler
{
- private const string ContextKey1 = "Umbraco.Web.Routing.RedirectTrackingEventHandler.1";
- private const string ContextKey2 = "Umbraco.Web.Routing.RedirectTrackingEventHandler.2";
- private const string ContextKey3 = "Umbraco.Web.Routing.RedirectTrackingEventHandler.3";
+ private const string ContextKey1 = "RedirectTrackingEventHandler.1";
+ private const string ContextKey2 = "RedirectTrackingEventHandler.2";
+ //private const string ContextKey3 = "RedirectTrackingEventHandler.3";
+ private const string ContextKey4 = "RedirectTrackingEventHandler.4";
///
protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
@@ -90,20 +92,80 @@ namespace Umbraco.Web.Routing
// rolled back items have to be published, so publishing will take care of that
}
+ /////
+ ///// Tracks a documents URLs during publishing in the current request
+ /////
+ //private static Dictionary> OldRoutes
+ //{
+ // get
+ // {
+ // var oldRoutes = RequestCache.GetCacheItem>>(
+ // ContextKey3,
+ // () => new Dictionary>());
+ // return oldRoutes;
+ // }
+ //}
+
+ private class PrePublishedContentContext
+ {
+ public static PrePublishedContentContext Empty
+ {
+ get { return new PrePublishedContentContext(null, null, null, null); }
+ }
+ /// Initializes a new instance of the class.
+ public PrePublishedContentContext(IContent entity, string urlSegment, ContextualPublishedContentCache contentCache, Func> descendentsDelegate)
+ {
+ if (entity == null) throw new ArgumentNullException("entity");
+ if (contentCache == null) throw new ArgumentNullException("contentCache");
+ if (descendentsDelegate == null) throw new ArgumentNullException("descendentsDelegate");
+ if (string.IsNullOrWhiteSpace(urlSegment)) throw new ArgumentException("Value cannot be null or whitespace.", "urlSegment");
+ Entity = entity;
+ UrlSegment = urlSegment;
+ ContentCache = contentCache;
+ DescendentsDelegate = descendentsDelegate;
+ }
+
+ public IContent Entity { get; set; }
+ public string UrlSegment { get; set; }
+ public Func> DescendentsDelegate { get; set; }
+ public ContextualPublishedContentCache ContentCache { get; set; }
+ }
+
///
- /// Tracks a documents URLs during publishing in the current request
+ /// Tracks the current doc's entity, url segment and delegate to retrieve it's old descendents during publishing in the current request
///
- private static Dictionary> OldRoutes
+ private static PrePublishedContentContext PrePublishedContent
{
get
{
- var oldRoutes = RequestCache.GetCacheItem>>(
- ContextKey3,
- () => new Dictionary>());
- return oldRoutes;
+ //return the item in the cache - otherwise initialize it to an empty instance
+ return RequestCache.GetCacheItem(ContextKey4, () => PrePublishedContentContext.Empty);
+ }
+ set
+ {
+ //clear it
+ RequestCache.ClearCacheItem(ContextKey4);
+ //force it into the cache
+ RequestCache.GetCacheItem(ContextKey4, () => value);
}
}
+ //private static Func> DescendentsOrSelfDelegate
+ //{
+ // get
+ // {
+ // //return the item in the cache - otherwise initialize it to an empty string
+ // return RequestCache.GetCacheItem>>(ContextKey4, () => (() => Enumerable.Empty()));
+ // }
+ // set
+ // {
+ // //clear it
+ // RequestCache.ClearCacheItem(ContextKey4);
+ // //force it into the cache
+ // RequestCache.GetCacheItem>>(ContextKey4, () => value);
+ // }
+ //}
+
private static bool LockedEvents
{
get
@@ -155,28 +217,26 @@ namespace Umbraco.Web.Routing
if (contentCache == null) return;
foreach (var entity in args.PublishedEntities)
- {
- //don't continue if this entity hasn't changed with regards to anything
- // that might change it's URLs
- if (entity.IsDirty() == false) continue;
+ {
+ var entityContent = contentCache.GetById(entity.Id);
+ if (entityContent == null) continue;
- if (entity.IsPropertyDirty("Name")
- || entity.IsPropertyDirty(Constants.Conventions.Content.UrlName)
- || entity.IsPropertyDirty(Constants.Conventions.Content.UrlAlias)
- || Moving)
- {
- var entityContent = contentCache.GetById(entity.Id);
- if (entityContent == null) continue;
- foreach (var x in entityContent.DescendantsOrSelf())
- {
- var route = contentCache.GetRouteById(x.Id);
- if (IsNotRoute(route)) continue;
- var wk = UnwrapToKey(x);
- if (wk == null) continue;
-
- OldRoutes[x.Id] = Tuple.Create(wk.Key, route);
- }
- }
+ PrePublishedContent = new PrePublishedContentContext(entity, entity.GetUrlSegment(), contentCache, () => entityContent.Descendants());
+
+ //if (Moving)
+ //{
+ // var entityContent = contentCache.GetById(entity.Id);
+ // if (entityContent == null) continue;
+ // foreach (var x in entityContent.Descendants())
+ // {
+ // var route = contentCache.GetRouteById(x.Id);
+ // if (IsNotRoute(route)) continue;
+ // var wk = UnwrapToKey(x);
+ // if (wk == null) continue;
+
+ // OldRoutes[x.Id] = Tuple.Create(wk.Key, route);
+ // }
+ //}
}
LockedEvents = true; // we only want to see the "first batch"
@@ -208,23 +268,62 @@ namespace Umbraco.Web.Routing
var serverRole = ApplicationContext.Current.GetCurrentServerRole();
if (serverRole == ServerRole.Master || serverRole == ServerRole.Single)
{
- if (RequestCache.GetCacheItem(ContextKey3) == null)
- return;
+ //copy local
+ var prePublishedContext = PrePublishedContent;
+ //cannot continue if this is empty
+ if (prePublishedContext.Entity == null) return;
+
+ //cannot continue if there is no published cache
+ var contentCache = GetPublishedCache();
+ if (contentCache == null) return;
+
+ //get the entity id out of the event args to compare with the id stored during publishing
+ if (cacheRefresherEventArgs.MessageType != MessageType.RefreshById || cacheRefresherEventArgs.MessageType != MessageType.RefreshByInstance) return;
+
+ var refreshedEntityId = cacheRefresherEventArgs.MessageType == MessageType.RefreshByInstance
+ ? ((IContent)cacheRefresherEventArgs.MessageObject).Id
+ : (int) cacheRefresherEventArgs.MessageObject;
+
+ //if it's not the id that we're targeting, don't continue
+ if (refreshedEntityId != prePublishedContext.Entity.Id) return;
+
+ //cannot continue if the entity is not found
+ var entityContent = contentCache.GetById(prePublishedContext.Entity.Id);
+ if (entityContent == null) return;
+
+ //now we can check if the segment has changed
+ var newSegment = prePublishedContext.Entity.GetUrlSegment();
try
{
- foreach (var oldRoute in OldRoutes)
+ if (Moving || newSegment != prePublishedContext.UrlSegment)
{
+ //it's changed!
+
// assuming we cannot have 'CacheUpdated' for only part of the infos else we'd need
// to set a flag in 'Published' to indicate which entities have been refreshed ok
- CreateRedirect(oldRoute.Key, oldRoute.Value.Item1, oldRoute.Value.Item2);
+ CreateRedirect(prePublishedContext.Entity.Id, prePublishedContext.Entity.Key, prePublishedContext.UrlSegment);
+
+ //iterate the old descendents and get their old routes
+ foreach (var x in prePublishedContext.DescendentsDelegate())
+ {
+ //get the old route from the old contextual cache
+ var oldRoute = prePublishedContext.ContentCache.GetRouteById(x.Id);
+ if (IsNotRoute(oldRoute)) continue;
+ var wk = UnwrapToKey(x);
+ if (wk == null) continue;
+
+ CreateRedirect(wk.Id, wk.Key, oldRoute);
+ }
}
}
finally
{
- OldRoutes.Clear();
- RequestCache.ClearCacheItem(ContextKey3);
- }
+ //set all refs to null
+ prePublishedContext.Entity = null;
+ prePublishedContext.ContentCache = null;
+ prePublishedContext.DescendentsDelegate = null;
+ }
}
}