Web.Routing - RoutesCache goes with PublishedCache
This commit is contained in:
@@ -27,7 +27,7 @@ namespace Umbraco.Tests.Routing
|
||||
var docRequest = new PublishedContentRequest(url, routingContext);
|
||||
var lookup = new ContentFinderByUrlAlias();
|
||||
|
||||
var result = lookup.TryFindDocument(docRequest);
|
||||
var result = lookup.TryFindContent(docRequest);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
Assert.AreEqual(docRequest.PublishedContent.Id, nodeMatch);
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace Umbraco.Tests.Routing
|
||||
Assert.AreEqual(expectedCulture, pcr.Culture.Name);
|
||||
|
||||
var finder = new ContentFinderByUrlAlias();
|
||||
var result = finder.TryFindDocument(pcr);
|
||||
var result = finder.TryFindContent(pcr);
|
||||
|
||||
if (expectedNode > 0)
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.Tests.Routing
|
||||
var lookup = new ContentFinderByIdPath();
|
||||
|
||||
|
||||
var result = lookup.TryFindDocument(docRequest);
|
||||
var result = lookup.TryFindContent(docRequest);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
Assert.AreEqual(docRequest.PublishedContent.Id, nodeMatch);
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Umbraco.Tests.Routing
|
||||
|
||||
SettingsForTests.HideTopLevelNodeFromPath = false;
|
||||
|
||||
var result = lookup.TryFindDocument(docRequest);
|
||||
var result = lookup.TryFindContent(docRequest);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
Assert.IsNotNull(docRequest.PublishedContent);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web.PublishedCache.LegacyXmlCache;
|
||||
using Umbraco.Web.Routing;
|
||||
using umbraco.BusinessLogic;
|
||||
using umbraco.cms.businesslogic.template;
|
||||
@@ -34,10 +36,10 @@ namespace Umbraco.Tests.Routing
|
||||
var routingContext = GetRoutingContext(urlString);
|
||||
var url = routingContext.UmbracoContext.CleanedUmbracoUrl; //very important to use the cleaned up umbraco url
|
||||
var docreq = new PublishedContentRequest(url, routingContext);
|
||||
var lookup = new ContentFinderByNiceUrl(false);
|
||||
var lookup = new ContentFinderByNiceUrl();
|
||||
SettingsForTests.HideTopLevelNodeFromPath = true;
|
||||
|
||||
var result = lookup.TryFindDocument(docreq);
|
||||
var result = lookup.TryFindContent(docreq);
|
||||
|
||||
if (expectedId > 0)
|
||||
{
|
||||
@@ -61,10 +63,10 @@ namespace Umbraco.Tests.Routing
|
||||
var routingContext = GetRoutingContext(urlString);
|
||||
var url = routingContext.UmbracoContext.CleanedUmbracoUrl; //very important to use the cleaned up umbraco url
|
||||
var docreq = new PublishedContentRequest(url, routingContext);
|
||||
var lookup = new ContentFinderByNiceUrl(false);
|
||||
var lookup = new ContentFinderByNiceUrl();
|
||||
SettingsForTests.HideTopLevelNodeFromPath = false;
|
||||
|
||||
var result = lookup.TryFindDocument(docreq);
|
||||
var result = lookup.TryFindContent(docreq);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
Assert.AreEqual(expectedId, docreq.PublishedContent.Id);
|
||||
|
||||
@@ -160,7 +160,7 @@ namespace Umbraco.Tests.Routing
|
||||
pcr.Engine.FindDomain();
|
||||
|
||||
var lookup = new ContentFinderByNiceUrl();
|
||||
var result = lookup.TryFindDocument(pcr);
|
||||
var result = lookup.TryFindContent(pcr);
|
||||
Assert.IsTrue(result);
|
||||
Assert.AreEqual(expectedId, pcr.PublishedContent.Id);
|
||||
}
|
||||
@@ -199,7 +199,7 @@ namespace Umbraco.Tests.Routing
|
||||
Assert.AreEqual(expectedCulture, pcr.Culture.Name);
|
||||
|
||||
var lookup = new ContentFinderByNiceUrl();
|
||||
var result = lookup.TryFindDocument(pcr);
|
||||
var result = lookup.TryFindContent(pcr);
|
||||
Assert.IsTrue(result);
|
||||
Assert.AreEqual(expectedId, pcr.PublishedContent.Id);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Umbraco.Tests.Routing
|
||||
routingContext.UmbracoContext.HttpContext.Request.Stub(x => x["umbPageID"])
|
||||
.Return(routingContext.UmbracoContext.HttpContext.Request.QueryString["umbPageID"]);
|
||||
|
||||
var result = lookup.TryFindDocument(docRequest);
|
||||
var result = lookup.TryFindContent(docRequest);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
Assert.AreEqual(docRequest.PublishedContent.Id, nodeMatch);
|
||||
|
||||
@@ -182,7 +182,7 @@ namespace Umbraco.Tests.Routing
|
||||
|
||||
SettingsForTests.HideTopLevelNodeFromPath = false;
|
||||
var finder = new ContentFinderByNiceUrl();
|
||||
var result = finder.TryFindDocument(pcr);
|
||||
var result = finder.TryFindContent(pcr);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
Assert.AreEqual(pcr.PublishedContent.Id, expectedNode);
|
||||
@@ -225,7 +225,7 @@ namespace Umbraco.Tests.Routing
|
||||
// find document
|
||||
SettingsForTests.HideTopLevelNodeFromPath = false;
|
||||
var finder = new ContentFinderByNiceUrl();
|
||||
var result = finder.TryFindDocument(pcr);
|
||||
var result = finder.TryFindContent(pcr);
|
||||
|
||||
// apply wildcard domain
|
||||
pcr.Engine.HandleWildcardDomains();
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web.PublishedCache.LegacyXmlCache;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Tests.Routing
|
||||
@@ -35,11 +36,6 @@ namespace Umbraco.Tests.Routing
|
||||
base.FreezeResolution();
|
||||
}
|
||||
|
||||
internal override IRoutesCache GetRoutesCache()
|
||||
{
|
||||
return new DefaultRoutesCache(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This checks that when we retreive a NiceUrl for multiple items that there are no issues with cache overlap
|
||||
/// and that they are all cached correctly.
|
||||
@@ -76,7 +72,9 @@ namespace Umbraco.Tests.Routing
|
||||
Assert.AreEqual(randomSample.Value, result);
|
||||
}
|
||||
|
||||
var cachedRoutes = ((DefaultRoutesCache)routingContext.RoutesCache).GetCachedRoutes();
|
||||
var cache = routingContext.UmbracoContext.ContentCache.InnerCache as PublishedContentCache;
|
||||
if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the legacy one is supported.");
|
||||
var cachedRoutes = cache.RoutesCache.GetCachedRoutes();
|
||||
Assert.AreEqual(8, cachedRoutes.Count);
|
||||
|
||||
foreach (var sample in samples)
|
||||
@@ -85,7 +83,7 @@ namespace Umbraco.Tests.Routing
|
||||
Assert.AreEqual(sample.Value, cachedRoutes[sample.Key]);
|
||||
}
|
||||
|
||||
var cachedIds = ((DefaultRoutesCache)routingContext.RoutesCache).GetCachedIds();
|
||||
var cachedIds = cache.RoutesCache.GetCachedIds();
|
||||
Assert.AreEqual(8, cachedIds.Count);
|
||||
|
||||
foreach (var sample in samples)
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Text;
|
||||
using System.Configuration;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web.PublishedCache.LegacyXmlCache;
|
||||
using Umbraco.Web.Routing;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
using umbraco.cms.businesslogic.language;
|
||||
@@ -28,11 +29,6 @@ namespace Umbraco.Tests.Routing
|
||||
base.FreezeResolution();
|
||||
}
|
||||
|
||||
internal override IRoutesCache GetRoutesCache()
|
||||
{
|
||||
return new DefaultRoutesCache(false);
|
||||
}
|
||||
|
||||
void InitializeLanguagesAndDomains()
|
||||
{
|
||||
var domains = Domain.GetDomains();
|
||||
@@ -314,10 +310,12 @@ namespace Umbraco.Tests.Routing
|
||||
ignore = routingContext.UrlProvider.GetUrl(100111, new Uri("http://domain2.com"), false);
|
||||
ignore = routingContext.UrlProvider.GetUrl(1002, new Uri("http://domain2.com"), false);
|
||||
|
||||
var cachedRoutes = ((DefaultRoutesCache)routingContext.RoutesCache).GetCachedRoutes();
|
||||
Assert.AreEqual(7, cachedRoutes.Count);
|
||||
var cache = routingContext.UmbracoContext.ContentCache.InnerCache as PublishedContentCache;
|
||||
if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the legacy one is supported.");
|
||||
var cachedRoutes = cache.RoutesCache.GetCachedRoutes();
|
||||
Assert.AreEqual(7, cachedRoutes.Count);
|
||||
|
||||
var cachedIds = ((DefaultRoutesCache)routingContext.RoutesCache).GetCachedIds();
|
||||
var cachedIds = cache.RoutesCache.GetCachedIds();
|
||||
Assert.AreEqual(7, cachedIds.Count);
|
||||
|
||||
CheckRoute(cachedRoutes, cachedIds, 1001, "1001/");
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web.PublishedCache.LegacyXmlCache;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
using umbraco.cms.businesslogic.language;
|
||||
using Umbraco.Web.Routing;
|
||||
@@ -37,7 +38,9 @@ namespace Umbraco.Tests.Routing
|
||||
Assert.AreEqual("http://domain2.com/1001-1-1/", routingContext.UrlProvider.GetUrl(100111, true));
|
||||
|
||||
// check that the proper route has been cached
|
||||
var cachedRoutes = ((DefaultRoutesCache)routingContext.RoutesCache).GetCachedRoutes();
|
||||
var cache = routingContext.UmbracoContext.ContentCache.InnerCache as PublishedContentCache;
|
||||
if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the legacy one is supported.");
|
||||
var cachedRoutes = cache.RoutesCache.GetCachedRoutes();
|
||||
Assert.AreEqual("10011/1001-1-1", cachedRoutes[100111]);
|
||||
|
||||
// route a rogue url
|
||||
@@ -49,12 +52,12 @@ namespace Umbraco.Tests.Routing
|
||||
|
||||
// check that it's been routed
|
||||
var lookup = new ContentFinderByNiceUrl();
|
||||
var result = lookup.TryFindDocument(pcr);
|
||||
var result = lookup.TryFindContent(pcr);
|
||||
Assert.IsTrue(result);
|
||||
Assert.AreEqual(100111, pcr.PublishedContent.Id);
|
||||
|
||||
// has the cache been polluted?
|
||||
cachedRoutes = ((DefaultRoutesCache)routingContext.RoutesCache).GetCachedRoutes();
|
||||
cachedRoutes = cache.RoutesCache.GetCachedRoutes();
|
||||
Assert.AreEqual("10011/1001-1-1", cachedRoutes[100111]); // no
|
||||
//Assert.AreEqual("1001/1001-1/1001-1-1", cachedRoutes[100111]); // yes
|
||||
|
||||
@@ -77,12 +80,6 @@ namespace Umbraco.Tests.Routing
|
||||
base.FreezeResolution();
|
||||
}
|
||||
|
||||
internal override IRoutesCache GetRoutesCache()
|
||||
{
|
||||
return new DefaultRoutesCache(false);
|
||||
}
|
||||
|
||||
|
||||
void InitializeLanguagesAndDomains()
|
||||
{
|
||||
var domains = Domain.GetDomains();
|
||||
|
||||
@@ -17,11 +17,6 @@ namespace Umbraco.Tests.Routing
|
||||
[TestFixture]
|
||||
public class uQueryGetNodeIdByUrlTests : BaseRoutingTest
|
||||
{
|
||||
internal override IRoutesCache GetRoutesCache()
|
||||
{
|
||||
return new DefaultRoutesCache(false);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -39,8 +34,7 @@ namespace Umbraco.Tests.Routing
|
||||
umbracoContext,
|
||||
lookups,
|
||||
new FakeLastChanceFinder(),
|
||||
urlProvider,
|
||||
GetRoutesCache());
|
||||
urlProvider);
|
||||
|
||||
//assign the routing context back to the umbraco context
|
||||
umbracoContext.RoutingContext = routingContext;
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Umbraco.Tests.Stubs
|
||||
{
|
||||
internal class FakeLastChanceFinder : IContentFinder
|
||||
{
|
||||
public bool TryFindDocument(PublishedContentRequest docRequest)
|
||||
public bool TryFindContent(PublishedContentRequest docRequest)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Tests.Stubs
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for testing, does not cache anything
|
||||
/// </summary>
|
||||
public class FakeRoutesCache : IRoutesCache
|
||||
{
|
||||
public void Store(int nodeId, string route)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string GetRoute(int nodeId)
|
||||
{
|
||||
return null; //default;
|
||||
}
|
||||
|
||||
public int GetNodeId(string route)
|
||||
{
|
||||
return 0; //default;
|
||||
}
|
||||
|
||||
public void ClearNode(int nodeId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -288,6 +288,8 @@ namespace Umbraco.Tests.TestHelpers
|
||||
return doc;
|
||||
};
|
||||
|
||||
PublishedContentCache.UnitTesting = true;
|
||||
|
||||
var ctx = new UmbracoContext(
|
||||
GetHttpContextFactory(url, routeData).HttpContext,
|
||||
ApplicationContext,
|
||||
@@ -310,11 +312,6 @@ namespace Umbraco.Tests.TestHelpers
|
||||
return factory;
|
||||
}
|
||||
|
||||
internal virtual IRoutesCache GetRoutesCache()
|
||||
{
|
||||
return new FakeRoutesCache();
|
||||
}
|
||||
|
||||
protected virtual string GetXmlContent(int templateId)
|
||||
{
|
||||
return @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
|
||||
@@ -33,8 +33,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
umbracoContext,
|
||||
Enumerable.Empty<IContentFinder>(),
|
||||
new FakeLastChanceFinder(),
|
||||
urlProvider,
|
||||
GetRoutesCache());
|
||||
urlProvider);
|
||||
|
||||
//assign the routing context back to the umbraco context
|
||||
umbracoContext.RoutingContext = routingContext;
|
||||
|
||||
@@ -347,7 +347,6 @@
|
||||
<Compile Include="PluginManagerExtensions.cs" />
|
||||
<Compile Include="PluginManagerTests.cs" />
|
||||
<Compile Include="Stubs\FakeLastChanceFinder.cs" />
|
||||
<Compile Include="Stubs\FakeRoutesCache.cs" />
|
||||
<Compile Include="TestHelpers\TestHelper.cs" />
|
||||
<Compile Include="EnumerableExtensionsTests.cs" />
|
||||
<Compile Include="IO\AbstractFileSystemTests.cs" />
|
||||
|
||||
@@ -12,10 +12,12 @@ namespace Umbraco.Web.PublishedCache
|
||||
internal abstract class ContextualPublishedCache
|
||||
{
|
||||
protected readonly UmbracoContext UmbracoContext;
|
||||
private readonly IPublishedCache _cache;
|
||||
|
||||
protected ContextualPublishedCache(UmbracoContext umbracoContext)
|
||||
protected ContextualPublishedCache(UmbracoContext umbracoContext, IPublishedCache cache)
|
||||
{
|
||||
UmbracoContext = umbracoContext;
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -23,13 +25,19 @@ namespace Umbraco.Web.PublishedCache
|
||||
/// </summary>
|
||||
/// <param name="contentId">The content unique identifier.</param>
|
||||
/// <returns>The content, or null.</returns>
|
||||
public abstract IPublishedContent GetById(int contentId);
|
||||
public virtual IPublishedContent GetById(int contentId)
|
||||
{
|
||||
return _cache.GetById(UmbracoContext, contentId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets contents at root.
|
||||
/// </summary>
|
||||
/// <returns>The contents.</returns>
|
||||
public abstract IEnumerable<IPublishedContent> GetAtRoot();
|
||||
public virtual IEnumerable<IPublishedContent> GetAtRoot()
|
||||
{
|
||||
return _cache.GetAtRoot(UmbracoContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a content resulting from an XPath query.
|
||||
@@ -37,7 +45,10 @@ namespace Umbraco.Web.PublishedCache
|
||||
/// <param name="xpath">The XPath query.</param>
|
||||
/// <param name="vars">Optional XPath variables.</param>
|
||||
/// <returns>The content, or null.</returns>
|
||||
public abstract IPublishedContent GetSingleByXPath(string xpath, Core.Xml.XPathVariable[] vars);
|
||||
public virtual IPublishedContent GetSingleByXPath(string xpath, Core.Xml.XPathVariable[] vars)
|
||||
{
|
||||
return _cache.GetSingleByXPath(UmbracoContext, xpath, vars);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets contents resulting from an XPath query.
|
||||
@@ -45,6 +56,18 @@ namespace Umbraco.Web.PublishedCache
|
||||
/// <param name="xpath">The XPath query.</param>
|
||||
/// <param name="vars">Optional XPath variables.</param>
|
||||
/// <returns>The contents.</returns>
|
||||
public abstract IEnumerable<IPublishedContent> GetByXPath(string xpath, Core.Xml.XPathVariable[] vars);
|
||||
public virtual IEnumerable<IPublishedContent> GetByXPath(string xpath, Core.Xml.XPathVariable[] vars)
|
||||
{
|
||||
return _cache.GetByXPath(UmbracoContext, xpath, vars);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the underlying non-contextual cache contains published content.
|
||||
/// </summary>
|
||||
/// <returns>A value indicating whether the underlying non-contextual cache contains published content.</returns>
|
||||
public virtual bool HasContent()
|
||||
{
|
||||
return _cache.HasContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Web.PublishedCache
|
||||
/// <param name="cache">A published content cache.</param>
|
||||
/// <param name="umbracoContext">A context.</param>
|
||||
public ContextualPublishedContentCache(IPublishedContentCache cache, UmbracoContext umbracoContext)
|
||||
: base(umbracoContext)
|
||||
: base(umbracoContext, cache)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
@@ -31,65 +31,31 @@ namespace Umbraco.Web.PublishedCache
|
||||
internal IPublishedContentCache InnerCache { get { return _cache; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a content identified by its unique identifier.
|
||||
/// Gets content identified by a route.
|
||||
/// </summary>
|
||||
/// <param name="contentId">The content unique identifier.</param>
|
||||
/// <param name="route">The route</param>
|
||||
/// <param name="hideTopLevelNode">FIXME</param>
|
||||
/// <returns>The content, or null.</returns>
|
||||
public override IPublishedContent GetById(int contentId)
|
||||
{
|
||||
return _cache.GetById(UmbracoContext, contentId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets contents at root.
|
||||
/// </summary>
|
||||
/// <returns>The contents.</returns>
|
||||
public override IEnumerable<IPublishedContent> GetAtRoot()
|
||||
{
|
||||
return _cache.GetAtRoot(UmbracoContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a content resulting from an XPath query.
|
||||
/// </summary>
|
||||
/// <param name="xpath">The XPath query.</param>
|
||||
/// <param name="vars">Optional XPath variables.</param>
|
||||
/// <returns>The content, or null.</returns>
|
||||
public override IPublishedContent GetSingleByXPath(string xpath, Core.Xml.XPathVariable[] vars)
|
||||
{
|
||||
return _cache.GetSingleByXPath(UmbracoContext, xpath, vars);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets contents resulting from an XPath query.
|
||||
/// </summary>
|
||||
/// <param name="xpath">The XPath query.</param>
|
||||
/// <param name="vars">Optional XPath variables.</param>
|
||||
/// <returns>The contents.</returns>
|
||||
public override IEnumerable<IPublishedContent> GetByXPath(string xpath, Core.Xml.XPathVariable[] vars)
|
||||
{
|
||||
return _cache.GetByXPath(UmbracoContext, xpath, vars);
|
||||
}
|
||||
|
||||
// FIXME do we want that one here?
|
||||
/// <remarks>A valid route is either a simple path eg <c>/foo/bar/nil</c> or a root node id and a path, eg <c>123/foo/bar/nil</c>.</remarks>
|
||||
public IPublishedContent GetByRoute(string route, bool? hideTopLevelNode = null)
|
||||
{
|
||||
return _cache.GetByRoute(UmbracoContext, route, hideTopLevelNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the route for a content identified by its unique identifier.
|
||||
/// </summary>
|
||||
/// <param name="contentId">The content unique identifier.</param>
|
||||
/// <returns>The route.</returns>
|
||||
public string GetRouteById(int contentId)
|
||||
{
|
||||
return _cache.GetRouteById(UmbracoContext, contentId);
|
||||
}
|
||||
|
||||
// FIXME do we want that one here?
|
||||
public IPublishedContent GetByUrlAlias(int rootNodeId, string alias)
|
||||
{
|
||||
return _cache.GetByUrlAlias(UmbracoContext, rootNodeId, alias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the underlying non-contextual cache contains published content.
|
||||
/// </summary>
|
||||
/// <returns>A value indicating whether the underlying non-contextual cache contains published content.</returns>
|
||||
public bool HasContent()
|
||||
{
|
||||
return _cache.HasContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,50 +19,9 @@ namespace Umbraco.Web.PublishedCache
|
||||
/// <param name="cache">A published media cache.</param>
|
||||
/// <param name="umbracoContext">A context.</param>
|
||||
public ContextualPublishedMediaCache(IPublishedMediaCache cache, UmbracoContext umbracoContext)
|
||||
: base(umbracoContext)
|
||||
: base(umbracoContext, cache)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a content identified by its unique identifier.
|
||||
/// </summary>
|
||||
/// <param name="contentId">The content unique identifier.</param>
|
||||
/// <returns>The content, or null.</returns>
|
||||
public override IPublishedContent GetById(int contentId)
|
||||
{
|
||||
return _cache.GetById(UmbracoContext, contentId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets contents at root.
|
||||
/// </summary>
|
||||
/// <returns>The contents.</returns>
|
||||
public override IEnumerable<IPublishedContent> GetAtRoot()
|
||||
{
|
||||
return _cache.GetAtRoot(UmbracoContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a content resulting from an XPath query.
|
||||
/// </summary>
|
||||
/// <param name="xpath">The XPath query.</param>
|
||||
/// <param name="vars">Optional XPath variables.</param>
|
||||
/// <returns>The content, or null.</returns>
|
||||
public override IPublishedContent GetSingleByXPath(string xpath, Core.Xml.XPathVariable[] vars)
|
||||
{
|
||||
return _cache.GetSingleByXPath(UmbracoContext, xpath, vars);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets contents resulting from an XPath query.
|
||||
/// </summary>
|
||||
/// <param name="xpath">The XPath query.</param>
|
||||
/// <param name="vars">Optional XPath variables.</param>
|
||||
/// <returns>The contents.</returns>
|
||||
public override IEnumerable<IPublishedContent> GetByXPath(string xpath, Core.Xml.XPathVariable[] vars)
|
||||
{
|
||||
return _cache.GetByXPath(UmbracoContext, xpath, vars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,11 @@ namespace Umbraco.Web.PublishedCache
|
||||
/// <returns>The contents.</returns>
|
||||
IEnumerable<IPublishedContent> GetByXPath(UmbracoContext umbracoContext, string xpath, XPathVariable[] vars);
|
||||
|
||||
// ... GetXPath single or multi
|
||||
// ... pass the helper and NOT the store, so we're consistent?!
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the cache contains published content.
|
||||
/// </summary>
|
||||
/// <returns>A value indicating whether the cache contains published content.</returns>
|
||||
bool HasContent();
|
||||
|
||||
//TODO: SD: We should make this happen! This will allow us to natively do a GetByDocumentType query
|
||||
// on the UmbracoHelper (or an internal DataContext that it uses, etc...)
|
||||
|
||||
@@ -9,16 +9,28 @@ namespace Umbraco.Web.PublishedCache
|
||||
{
|
||||
internal interface IPublishedContentCache : IPublishedCache
|
||||
{
|
||||
// FIXME do we want that one?
|
||||
/// <summary>
|
||||
/// Gets content identified by a route.
|
||||
/// </summary>
|
||||
/// <param name="umbracoContext">The context.</param>
|
||||
/// <param name="route">The route</param>
|
||||
/// <param name="hideTopLevelNode">A value forcing the HideTopLevelNode setting.</param>
|
||||
/// <returns>The content, or null.</returns>
|
||||
/// <remarks>
|
||||
/// <para>A valid route is either a simple path eg <c>/foo/bar/nil</c> or a root node id and a path, eg <c>123/foo/bar/nil</c>.</para>
|
||||
/// <para>If <param name="hideTopLevelNode" /> is <c>null</c> then the settings value is used.</para>
|
||||
/// </remarks>
|
||||
IPublishedContent GetByRoute(UmbracoContext umbracoContext, string route, bool? hideTopLevelNode = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the route for a content identified by its unique identifier.
|
||||
/// </summary>
|
||||
/// <param name="umbracoContext">The context.</param>
|
||||
/// <param name="contentId">The content unique identifier.</param>
|
||||
/// <returns>The route.</returns>
|
||||
string GetRouteById(UmbracoContext umbracoContext, int contentId);
|
||||
|
||||
// FIXME do we want that one?
|
||||
IPublishedContent GetByUrlAlias(UmbracoContext umbracoContext, int rootNodeId, string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the cache contains published content.
|
||||
/// </summary>
|
||||
/// <returns>A value indicating whether the cache contains published content.</returns>
|
||||
bool HasContent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Xml;
|
||||
using Umbraco.Web.Routing;
|
||||
using umbraco;
|
||||
using System.Linq;
|
||||
using umbraco.BusinessLogic;
|
||||
@@ -13,9 +16,180 @@ namespace Umbraco.Web.PublishedCache.LegacyXmlCache
|
||||
{
|
||||
internal class PublishedContentCache : IPublishedContentCache
|
||||
{
|
||||
#region XPath Strings
|
||||
#region Routes cache
|
||||
|
||||
class XPathStringsDefinition
|
||||
private readonly RoutesCache _routesCache = new RoutesCache(!UnitTesting);
|
||||
|
||||
// for INTERNAL, UNIT TESTS use ONLY
|
||||
internal RoutesCache RoutesCache { get { return _routesCache; } }
|
||||
|
||||
// for INTERNAL, UNIT TESTS use ONLY
|
||||
internal static bool UnitTesting = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets content identified by a route.
|
||||
/// </summary>
|
||||
/// <param name="umbracoContext">The context.</param>
|
||||
/// <param name="route">The route</param>
|
||||
/// <param name="hideTopLevelNode">A value forcing the HideTopLevelNode setting.</param>
|
||||
/// <returns>The content, or null.</returns>
|
||||
/// <remarks>
|
||||
/// <para>A valid route is either a simple path eg <c>/foo/bar/nil</c> or a root node id and a path, eg <c>123/foo/bar/nil</c>.</para>
|
||||
/// <para>If <param name="hideTopLevelNode" /> is <c>null</c> then the settings value is used.</para>
|
||||
/// </remarks>
|
||||
public IPublishedContent GetByRoute(UmbracoContext umbracoContext, string route, bool? hideTopLevelNode = null)
|
||||
{
|
||||
if (route == null) throw new ArgumentNullException("route");
|
||||
|
||||
// try to get from cache if not previewing
|
||||
var contentId = umbracoContext.InPreviewMode
|
||||
? 0
|
||||
: _routesCache.GetNodeId(route);
|
||||
|
||||
// if found id in cache then get corresponding content
|
||||
// and clear cache if not found - for whatever reason
|
||||
IPublishedContent content = null;
|
||||
if (contentId > 0)
|
||||
{
|
||||
content = GetById(umbracoContext, contentId);
|
||||
if (content == null)
|
||||
_routesCache.ClearNode(contentId);
|
||||
}
|
||||
|
||||
// still have nothing? actually determine the id
|
||||
hideTopLevelNode = hideTopLevelNode ?? GlobalSettings.HideTopLevelNodeFromPath; // default = settings
|
||||
content = content ?? DetermineIdByRoute(umbracoContext, route, hideTopLevelNode.Value);
|
||||
|
||||
// cache if we have a content and not previewing
|
||||
if (content != null && !umbracoContext.InPreviewMode)
|
||||
{
|
||||
var domainRootNodeId = route.StartsWith("/") ? -1 : int.Parse(route.Substring(0, route.IndexOf('/')));
|
||||
var iscanon = !UnitTesting && !DomainHelper.ExistsDomainInPath(DomainHelper.GetAllDomains(false), content.Path, domainRootNodeId);
|
||||
// and only if this is the canonical url (the one GetUrl would return)
|
||||
if (iscanon)
|
||||
_routesCache.Store(contentId, route);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the route for a content identified by its unique identifier.
|
||||
/// </summary>
|
||||
/// <param name="umbracoContext">The context.</param>
|
||||
/// <param name="contentId">The content unique identifier.</param>
|
||||
/// <returns>The route.</returns>
|
||||
public string GetRouteById(UmbracoContext umbracoContext, int contentId)
|
||||
{
|
||||
// try to get from cache if not previewing
|
||||
var route = umbracoContext.InPreviewMode
|
||||
? null
|
||||
: _routesCache.GetRoute(contentId);
|
||||
|
||||
// if found in cache then return
|
||||
if (route != null)
|
||||
return route;
|
||||
|
||||
// else actually determine the route
|
||||
route = DetermineRouteById(umbracoContext, contentId);
|
||||
|
||||
// cache if we have a route and not previewing
|
||||
if (route != null && !umbracoContext.InPreviewMode)
|
||||
_routesCache.Store(contentId, route);
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
IPublishedContent DetermineIdByRoute(UmbracoContext umbracoContext, string route, bool hideTopLevelNode)
|
||||
{
|
||||
if (route == null) throw new ArgumentNullException("route");
|
||||
|
||||
//the route always needs to be lower case because we only store the urlName attribute in lower case
|
||||
route = route.ToLowerInvariant();
|
||||
|
||||
var pos = route.IndexOf('/');
|
||||
var path = pos == 0 ? route : route.Substring(pos);
|
||||
var startNodeId = pos == 0 ? 0 : int.Parse(route.Substring(0, pos));
|
||||
IEnumerable<XPathVariable> vars;
|
||||
|
||||
var xpath = CreateXpathQuery(startNodeId, path, hideTopLevelNode, out vars);
|
||||
|
||||
//check if we can find the node in our xml cache
|
||||
var content = GetSingleByXPath(umbracoContext, xpath, vars == null ? null : vars.ToArray());
|
||||
|
||||
// if hideTopLevelNodePath is true then for url /foo we looked for /*/foo
|
||||
// but maybe that was the url of a non-default top-level node, so we also
|
||||
// have to look for /foo (see note in ApplyHideTopLevelNodeFromPath).
|
||||
if (content == null && hideTopLevelNode && path.Length > 1 && path.IndexOf('/', 1) < 0)
|
||||
{
|
||||
xpath = CreateXpathQuery(startNodeId, path, false, out vars);
|
||||
content = GetSingleByXPath(umbracoContext, xpath, vars == null ? null : vars.ToArray());
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
string DetermineRouteById(UmbracoContext umbracoContext, int contentId)
|
||||
{
|
||||
var node = GetById(umbracoContext, contentId);
|
||||
if (node == null)
|
||||
return null;
|
||||
|
||||
// walk up from that node until we hit a node with a domain,
|
||||
// or we reach the content root, collecting urls in the way
|
||||
var pathParts = new List<string>();
|
||||
var n = node;
|
||||
var hasDomains = DomainHelper.NodeHasDomains(n.Id);
|
||||
while (!hasDomains && n != null) // n is null at root
|
||||
{
|
||||
// get the url
|
||||
var urlName = n.UrlName;
|
||||
pathParts.Add(urlName);
|
||||
|
||||
// move to parent node
|
||||
n = n.Parent;
|
||||
hasDomains = n != null && DomainHelper.NodeHasDomains(n.Id);
|
||||
}
|
||||
|
||||
// no domain, respect HideTopLevelNodeFromPath for legacy purposes
|
||||
if (!hasDomains && global::umbraco.GlobalSettings.HideTopLevelNodeFromPath)
|
||||
ApplyHideTopLevelNodeFromPath(umbracoContext, node, pathParts);
|
||||
|
||||
// assemble the route
|
||||
pathParts.Reverse();
|
||||
var path = "/" + string.Join("/", pathParts); // will be "/" or "/foo" or "/foo/bar" etc
|
||||
var route = (n == null ? "" : n.Id.ToString(CultureInfo.InvariantCulture)) + path;
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
static void ApplyHideTopLevelNodeFromPath(UmbracoContext umbracoContext, IPublishedContent node, IList<string> pathParts)
|
||||
{
|
||||
// in theory if hideTopLevelNodeFromPath is true, then there should be only once
|
||||
// top-level node, or else domains should be assigned. but for backward compatibility
|
||||
// we add this check - we look for the document matching "/" and if it's not us, then
|
||||
// we do not hide the top level path
|
||||
// it has to be taken care of in GetByRoute too so if
|
||||
// "/foo" fails (looking for "/*/foo") we try also "/foo".
|
||||
// this does not make much sense anyway esp. if both "/foo/" and "/bar/foo" exist, but
|
||||
// that's the way it works pre-4.10 and we try to be backward compat for the time being
|
||||
if (node.Parent == null)
|
||||
{
|
||||
var rootNode = umbracoContext.ContentCache.GetByRoute("/", true);
|
||||
if (rootNode.Id == node.Id) // remove only if we're the default node
|
||||
pathParts.RemoveAt(pathParts.Count - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pathParts.RemoveAt(pathParts.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region XPath Strings
|
||||
|
||||
class XPathStringsDefinition
|
||||
{
|
||||
public int Version { get; private set; }
|
||||
|
||||
@@ -134,39 +308,6 @@ namespace Umbraco.Web.PublishedCache.LegacyXmlCache
|
||||
return ConvertToDocuments(nodes);
|
||||
}
|
||||
|
||||
//FIXME keep here or remove?
|
||||
public IPublishedContent GetByRoute(UmbracoContext umbracoContext, string route, bool? hideTopLevelNode = null)
|
||||
{
|
||||
if (route == null) throw new ArgumentNullException("route");
|
||||
|
||||
//set the default to be what is in the settings
|
||||
hideTopLevelNode = hideTopLevelNode ?? GlobalSettings.HideTopLevelNodeFromPath;
|
||||
|
||||
//the route always needs to be lower case because we only store the urlName attribute in lower case
|
||||
route = route.ToLowerInvariant();
|
||||
|
||||
var pos = route.IndexOf('/');
|
||||
var path = pos == 0 ? route : route.Substring(pos);
|
||||
var startNodeId = pos == 0 ? 0 : int.Parse(route.Substring(0, pos));
|
||||
IEnumerable<XPathVariable> vars;
|
||||
|
||||
var xpath = CreateXpathQuery(startNodeId, path, hideTopLevelNode.Value, out vars);
|
||||
|
||||
//check if we can find the node in our xml cache
|
||||
var content = GetSingleByXPath(umbracoContext, xpath, vars == null ? null : vars.ToArray());
|
||||
|
||||
// if hideTopLevelNodePath is true then for url /foo we looked for /*/foo
|
||||
// but maybe that was the url of a non-default top-level node, so we also
|
||||
// have to look for /foo (see note in NiceUrlProvider).
|
||||
if (content == null && hideTopLevelNode.Value && path.Length > 1 && path.IndexOf('/', 1) < 0)
|
||||
{
|
||||
xpath = CreateXpathQuery(startNodeId, path, false, out vars);
|
||||
content = GetSingleByXPath(umbracoContext, xpath, vars == null ? null : vars.ToArray());
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
// FIXME MOVE THAT ONE OUT OF HERE?
|
||||
public IPublishedContent GetByUrlAlias(UmbracoContext umbracoContext, int rootNodeId, string alias)
|
||||
{
|
||||
|
||||
@@ -77,6 +77,8 @@ namespace Umbraco.Web.PublishedCache.LegacyXmlCache
|
||||
throw new NotImplementedException("PublishedMediaCache does not support XPath queries.");
|
||||
}
|
||||
|
||||
public bool HasContent() { throw new NotImplementedException(); }
|
||||
|
||||
private ExamineManager GetExamineManagerSafe()
|
||||
{
|
||||
try
|
||||
|
||||
152
src/Umbraco.Web/PublishedCache/LegacyXmlCache/RoutesCache.cs
Normal file
152
src/Umbraco.Web/PublishedCache/LegacyXmlCache/RoutesCache.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.LegacyXmlCache
|
||||
{
|
||||
class RoutesCache
|
||||
{
|
||||
private ConcurrentDictionary<int, string> _routes;
|
||||
private ConcurrentDictionary<string, int> _nodeIds;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RoutesCache"/> class.
|
||||
/// </summary>
|
||||
public RoutesCache()
|
||||
: this(true)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RoutesCache"/> class.
|
||||
/// </summary>
|
||||
internal RoutesCache(bool bindToEvents)
|
||||
{
|
||||
Clear();
|
||||
|
||||
if (bindToEvents)
|
||||
{
|
||||
Resolution.Frozen += ResolutionFrozen;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Once resolution is frozen, then we can bind to the events that we require
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="args"></param>
|
||||
private void ResolutionFrozen(object s, EventArgs args)
|
||||
{
|
||||
// content - whenever the entire XML cache is rebuilt (from disk cache or from database)
|
||||
// we must clear the cache entirely
|
||||
global::umbraco.content.AfterRefreshContent += (sender, e) => Clear();
|
||||
|
||||
// document - whenever a document is updated in, or removed from, the XML cache
|
||||
// we must clear the cache - at the moment, we clear the entire cache
|
||||
// TODO could we do partial updates instead of clearing the whole cache?
|
||||
global::umbraco.content.AfterUpdateDocumentCache += (sender, e) => Clear();
|
||||
global::umbraco.content.AfterClearDocumentCache += (sender, e) => Clear();
|
||||
|
||||
// domains - whenever a domain change we must clear the cache
|
||||
// because routes contain the id of root nodes of domains
|
||||
// TODO could we do partial updates instead of clearing the whole cache?
|
||||
global::umbraco.cms.businesslogic.web.Domain.AfterDelete += (sender, e) => Clear();
|
||||
global::umbraco.cms.businesslogic.web.Domain.AfterSave += (sender, e) => Clear();
|
||||
global::umbraco.cms.businesslogic.web.Domain.New += (sender, e) => Clear();
|
||||
|
||||
// FIXME
|
||||
// the content class needs to be refactored - at the moment
|
||||
// content.XmlContentInternal setter does not trigger any event
|
||||
// content.UpdateDocumentCache(List<Document> Documents) does not trigger any event
|
||||
// content.RefreshContentFromDatabaseAsync triggers AfterRefresh _while_ refreshing
|
||||
// etc...
|
||||
// in addition some events do not make sense... we trigger Publish when moving
|
||||
// a node, which we should not (the node is moved, not published...) etc.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used ONLY for unit tests
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal IDictionary<int, string> GetCachedRoutes()
|
||||
{
|
||||
return _routes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used ONLY for unit tests
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal IDictionary<string, int> GetCachedIds()
|
||||
{
|
||||
return _nodeIds;
|
||||
}
|
||||
|
||||
#region Public
|
||||
|
||||
/// <summary>
|
||||
/// Stores a route for a node.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identified.</param>
|
||||
/// <param name="route">The route.</param>
|
||||
public void Store(int nodeId, string route)
|
||||
{
|
||||
_routes.AddOrUpdate(nodeId, i => route, (i, s) => route);
|
||||
_nodeIds.AddOrUpdate(route, i => nodeId, (i, s) => nodeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a route for a node.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identifier.</param>
|
||||
/// <returns>The route for the node, else null.</returns>
|
||||
public string GetRoute(int nodeId)
|
||||
{
|
||||
string val;
|
||||
_routes.TryGetValue(nodeId, out val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a node for a route.
|
||||
/// </summary>
|
||||
/// <param name="route">The route.</param>
|
||||
/// <returns>The node identified for the route, else zero.</returns>
|
||||
public int GetNodeId(string route)
|
||||
{
|
||||
int val;
|
||||
_nodeIds.TryGetValue(route, out val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the route for a node.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identifier.</param>
|
||||
public void ClearNode(int nodeId)
|
||||
{
|
||||
if (!_routes.ContainsKey(nodeId)) return;
|
||||
|
||||
string key;
|
||||
if (!_routes.TryGetValue(nodeId, out key)) return;
|
||||
|
||||
int val;
|
||||
_nodeIds.TryRemove(key, out val);
|
||||
string val2;
|
||||
_routes.TryRemove(nodeId, out val2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all routes.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
_routes = new ConcurrentDictionary<int, string>();
|
||||
_nodeIds = new ConcurrentDictionary<string, int>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace Umbraco.Web.Routing
|
||||
/// </summary>
|
||||
/// <param name="docRequest">The <c>PublishedContentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public bool TryFindDocument(PublishedContentRequest docRequest)
|
||||
public bool TryFindContent(PublishedContentRequest docRequest)
|
||||
{
|
||||
IPublishedContent node = null;
|
||||
var path = docRequest.Uri.GetAbsolutePathDecoded();
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Web.Routing
|
||||
/// </summary>
|
||||
/// <param name="pcr">The <c>PublishedContentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public bool TryFindDocument(PublishedContentRequest pcr)
|
||||
public bool TryFindContent(PublishedContentRequest pcr)
|
||||
{
|
||||
LogHelper.Debug<ContentFinderByLegacy404>("Looking for a page to handle 404.");
|
||||
|
||||
|
||||
@@ -12,28 +12,12 @@ namespace Umbraco.Web.Routing
|
||||
/// </remarks>
|
||||
internal class ContentFinderByNiceUrl : IContentFinder
|
||||
{
|
||||
private readonly bool _doDomainLookup;
|
||||
|
||||
public ContentFinderByNiceUrl()
|
||||
{
|
||||
_doDomainLookup = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contructor with flag to set whether we lookup domains in the repo to match the url or not
|
||||
/// </summary>
|
||||
/// <param name="doDomainLookup"></param>
|
||||
internal ContentFinderByNiceUrl(bool doDomainLookup)
|
||||
{
|
||||
_doDomainLookup = doDomainLookup;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find and assign an Umbraco document to a <c>PublishedContentRequest</c>.
|
||||
/// </summary>
|
||||
/// <param name="docRequest">The <c>PublishedContentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public virtual bool TryFindDocument(PublishedContentRequest docRequest)
|
||||
public virtual bool TryFindContent(PublishedContentRequest docRequest)
|
||||
{
|
||||
string route;
|
||||
if (docRequest.HasDomain)
|
||||
@@ -41,7 +25,7 @@ namespace Umbraco.Web.Routing
|
||||
else
|
||||
route = docRequest.Uri.GetAbsolutePathDecoded();
|
||||
|
||||
var node = LookupDocumentNode(docRequest, route);
|
||||
var node = FindContent(docRequest, route);
|
||||
return node != null;
|
||||
}
|
||||
|
||||
@@ -51,62 +35,22 @@ namespace Umbraco.Web.Routing
|
||||
/// <param name="docreq">The document request.</param>
|
||||
/// <param name="route">The route.</param>
|
||||
/// <returns>The document node, or null.</returns>
|
||||
protected IPublishedContent LookupDocumentNode(PublishedContentRequest docreq, string route)
|
||||
protected IPublishedContent FindContent(PublishedContentRequest docreq, string route)
|
||||
{
|
||||
LogHelper.Debug<ContentFinderByNiceUrl>("Test route \"{0}\"", () => route);
|
||||
|
||||
// first ask the cache for a node
|
||||
// return '0' if in preview mode
|
||||
var nodeId = !docreq.RoutingContext.UmbracoContext.InPreviewMode
|
||||
? docreq.RoutingContext.RoutesCache.GetNodeId(route)
|
||||
: 0;
|
||||
|
||||
// if a node was found, get it by id and ensure it exists
|
||||
// else clear the cache
|
||||
IPublishedContent node = null;
|
||||
if (nodeId > 0)
|
||||
var node = docreq.RoutingContext.UmbracoContext.ContentCache.GetByRoute(route);
|
||||
if (node != null)
|
||||
{
|
||||
node = docreq.RoutingContext.UmbracoContext.ContentCache.GetById(nodeId);
|
||||
|
||||
if (node != null)
|
||||
{
|
||||
docreq.PublishedContent = node;
|
||||
LogHelper.Debug<ContentFinderByNiceUrl>("Cache hit, id={0}", () => nodeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
docreq.RoutingContext.RoutesCache.ClearNode(nodeId);
|
||||
}
|
||||
docreq.PublishedContent = node;
|
||||
LogHelper.Debug<ContentFinderByNiceUrl>("Got content, id={0}", () => node.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<ContentFinderByNiceUrl>("No match.");
|
||||
}
|
||||
|
||||
// if we still have no node, get it by route
|
||||
if (node == null)
|
||||
{
|
||||
LogHelper.Debug<ContentFinderByNiceUrl>("Cache miss, query");
|
||||
node = docreq.RoutingContext.UmbracoContext.ContentCache.GetByRoute(route);
|
||||
|
||||
if (node != null)
|
||||
{
|
||||
docreq.PublishedContent = node;
|
||||
LogHelper.Debug<ContentFinderByNiceUrl>("Query matches, id={0}", () => docreq.PublishedContent.Id);
|
||||
|
||||
var rootNodeId = docreq.Domain == null ? (int?) null : docreq.Domain.RootNodeId;
|
||||
var iscanon = _doDomainLookup && !DomainHelper.ExistsDomainInPath(DomainHelper.GetAllDomains(false), node.Path, rootNodeId);
|
||||
if (!iscanon)
|
||||
LogHelper.Debug<ContentFinderByNiceUrl>("Non canonical url");
|
||||
|
||||
// do not store if previewing or if non-canonical
|
||||
if (!docreq.RoutingContext.UmbracoContext.InPreviewMode && iscanon)
|
||||
docreq.RoutingContext.RoutesCache.Store(docreq.PublishedContent.Id, route);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<ContentFinderByNiceUrl>("Query does not match");
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Web.Routing
|
||||
/// <param name="docRequest">The <c>PublishedContentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
/// <remarks>If successful, also assigns the template.</remarks>
|
||||
public override bool TryFindDocument(PublishedContentRequest docRequest)
|
||||
public override bool TryFindContent(PublishedContentRequest docRequest)
|
||||
{
|
||||
IPublishedContent node = null;
|
||||
string path = docRequest.Uri.GetAbsolutePathDecoded();
|
||||
@@ -39,7 +39,7 @@ namespace Umbraco.Web.Routing
|
||||
LogHelper.Debug<ContentFinderByNiceUrlAndTemplate>("Valid template: \"{0}\"", () => templateAlias);
|
||||
|
||||
var route = docRequest.HasDomain ? (docRequest.Domain.RootNodeId.ToString() + path) : path;
|
||||
node = LookupDocumentNode(docRequest, route);
|
||||
node = FindContent(docRequest, route);
|
||||
|
||||
if (node != null)
|
||||
docRequest.TemplateModel = template;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Web.Routing
|
||||
/// </summary>
|
||||
/// <param name="pcr">The <c>PublishedContentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public bool TryFindDocument(PublishedContentRequest pcr)
|
||||
public bool TryFindContent(PublishedContentRequest pcr)
|
||||
{
|
||||
var type = typeof(THandler);
|
||||
var handler = GetHandler(type);
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Umbraco.Web.Routing
|
||||
/// </summary>
|
||||
/// <param name="docRequest">The <c>PublishedContentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public bool TryFindDocument(PublishedContentRequest docRequest)
|
||||
public bool TryFindContent(PublishedContentRequest docRequest)
|
||||
{
|
||||
HandlePageNotFound(docRequest);
|
||||
return docRequest.HasPublishedContent;
|
||||
@@ -55,7 +55,7 @@ namespace Umbraco.Web.Routing
|
||||
{
|
||||
var finderName = finder.GetType().FullName;
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Replace handler '{0}' by new finder '{1}'.", () => handlerName, () => finderName);
|
||||
if (finder.TryFindDocument(docRequest))
|
||||
if (finder.TryFindContent(docRequest))
|
||||
{
|
||||
// do NOT set docRequest.PublishedContent again here as
|
||||
// it would clear any template that the finder might have set
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Umbraco.Web.Routing
|
||||
/// </remarks>
|
||||
internal class ContentFinderByPageIdQuery : IContentFinder
|
||||
{
|
||||
public bool TryFindDocument(PublishedContentRequest docRequest)
|
||||
public bool TryFindContent(PublishedContentRequest docRequest)
|
||||
{
|
||||
int pageId;
|
||||
if (int.TryParse(docRequest.RoutingContext.UmbracoContext.HttpContext.Request["umbPageID"], out pageId))
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Umbraco.Web.Routing
|
||||
/// </summary>
|
||||
/// <param name="docRequest">The <c>PublishedContentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public override bool TryFindDocument(PublishedContentRequest docRequest)
|
||||
public override bool TryFindContent(PublishedContentRequest docRequest)
|
||||
{
|
||||
IPublishedContent node = null;
|
||||
var path = docRequest.Uri.GetAbsolutePathDecoded();
|
||||
@@ -38,7 +38,7 @@ namespace Umbraco.Web.Routing
|
||||
LogHelper.Debug<ContentFinderByProfile>("Path \"{0}\" is the profile path", () => path);
|
||||
|
||||
var route = docRequest.HasDomain ? (docRequest.Domain.RootNodeId.ToString() + path) : path;
|
||||
node = LookupDocumentNode(docRequest, route);
|
||||
node = FindContent(docRequest, route);
|
||||
|
||||
if (node != null)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Umbraco.Web.Routing
|
||||
/// </summary>
|
||||
/// <param name="docRequest">The <c>PublishedContentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public bool TryFindDocument(PublishedContentRequest docRequest)
|
||||
public bool TryFindContent(PublishedContentRequest docRequest)
|
||||
{
|
||||
IPublishedContent node = null;
|
||||
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a default implementation of <see cref="IRoutesCache"/>.
|
||||
/// </summary>
|
||||
internal class DefaultRoutesCache : IRoutesCache
|
||||
{
|
||||
private ConcurrentDictionary<int, string> _routes;
|
||||
private ConcurrentDictionary<string, int> _nodeIds;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DefaultRoutesCache"/> class.
|
||||
/// </summary>
|
||||
public DefaultRoutesCache() : this(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal DefaultRoutesCache(bool bindToEvents)
|
||||
{
|
||||
Clear();
|
||||
|
||||
if (bindToEvents)
|
||||
{
|
||||
Resolution.Frozen += ResolutionFrozen;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Once resolution is frozen, then we can bind to the events that we require
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="args"></param>
|
||||
void ResolutionFrozen(object s, EventArgs args)
|
||||
{
|
||||
// content - whenever the entire XML cache is rebuilt (from disk cache or from database)
|
||||
// we must clear the cache entirely
|
||||
global::umbraco.content.AfterRefreshContent += (sender, e) => Clear();
|
||||
|
||||
// document - whenever a document is updated in, or removed from, the XML cache
|
||||
// we must clear the cache - at the moment, we clear the entire cache
|
||||
// TODO could we do partial updates instead of clearing the whole cache?
|
||||
global::umbraco.content.AfterUpdateDocumentCache += (sender, e) => Clear();
|
||||
global::umbraco.content.AfterClearDocumentCache += (sender, e) => Clear();
|
||||
|
||||
// domains - whenever a domain change we must clear the cache
|
||||
// because routes contain the id of root nodes of domains
|
||||
// TODO could we do partial updates instead of clearing the whole cache?
|
||||
global::umbraco.cms.businesslogic.web.Domain.AfterDelete += (sender, e) => Clear();
|
||||
global::umbraco.cms.businesslogic.web.Domain.AfterSave += (sender, e) => Clear();
|
||||
global::umbraco.cms.businesslogic.web.Domain.New += (sender, e) => Clear();
|
||||
|
||||
// FIXME
|
||||
// the content class needs to be refactored - at the moment
|
||||
// content.XmlContentInternal setter does not trigger any event
|
||||
// content.UpdateDocumentCache(List<Document> Documents) does not trigger any event
|
||||
// content.RefreshContentFromDatabaseAsync triggers AfterRefresh _while_ refreshing
|
||||
// etc...
|
||||
// in addition some events do not make sense... we trigger Publish when moving
|
||||
// a node, which we should not (the node is moved, not published...) etc.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used ONLY for unit tests
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal IDictionary<int, string> GetCachedRoutes()
|
||||
{
|
||||
return _routes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used ONLY for unit tests
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal IDictionary<string, int> GetCachedIds()
|
||||
{
|
||||
return _nodeIds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a route for a node.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identified.</param>
|
||||
/// <param name="route">The route.</param>
|
||||
public void Store(int nodeId, string route)
|
||||
{
|
||||
_routes.AddOrUpdate(nodeId, i => route, (i, s) => route);
|
||||
_nodeIds.AddOrUpdate(route, i => nodeId, (i, s) => nodeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a route for a node.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identifier.</param>
|
||||
/// <returns>The route for the node, else null.</returns>
|
||||
public string GetRoute(int nodeId)
|
||||
{
|
||||
string val;
|
||||
_routes.TryGetValue(nodeId, out val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a node for a route.
|
||||
/// </summary>
|
||||
/// <param name="route">The route.</param>
|
||||
/// <returns>The node identified for the route, else zero.</returns>
|
||||
public int GetNodeId(string route)
|
||||
{
|
||||
int val;
|
||||
_nodeIds.TryGetValue(route, out val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the route for a node.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identifier.</param>
|
||||
public void ClearNode(int nodeId)
|
||||
{
|
||||
if (_routes.ContainsKey(nodeId))
|
||||
{
|
||||
string key;
|
||||
if (_routes.TryGetValue(nodeId, out key))
|
||||
{
|
||||
int val;
|
||||
_nodeIds.TryRemove(key, out val);
|
||||
string val2;
|
||||
_routes.TryRemove(nodeId, out val2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all routes.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
_routes = new ConcurrentDictionary<int, string>();
|
||||
_nodeIds = new ConcurrentDictionary<string, int>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,69 +31,25 @@ namespace Umbraco.Web.Routing
|
||||
/// </remarks>
|
||||
public virtual string GetUrl(UmbracoContext umbracoContext, int id, Uri current, UrlProviderMode mode)
|
||||
{
|
||||
DomainAndUri domainUri;
|
||||
string path;
|
||||
|
||||
if (!current.IsAbsoluteUri)
|
||||
// ReSharper disable LocalizableElement
|
||||
throw new ArgumentException("Current url must be absolute.", "current");
|
||||
// ReSharper restore LocalizableElement
|
||||
|
||||
// do not read cache if previewing
|
||||
var route = umbracoContext.InPreviewMode
|
||||
? null
|
||||
: umbracoContext.RoutingContext.RoutesCache.GetRoute(id);
|
||||
// will not use cache if previewing
|
||||
var route = umbracoContext.ContentCache.GetRouteById(id);
|
||||
|
||||
if (!string.IsNullOrEmpty(route))
|
||||
if (string.IsNullOrWhiteSpace(route))
|
||||
{
|
||||
// there was a route in the cache - extract domainUri and path
|
||||
// route is /<path> or <domainRootId>/<path>
|
||||
var pos = route.IndexOf('/');
|
||||
path = pos == 0 ? route : route.Substring(pos);
|
||||
domainUri = pos == 0 ? null : DomainHelper.DomainForNode(int.Parse(route.Substring(0, pos)), current);
|
||||
LogHelper.Warn<DefaultUrlProvider>(
|
||||
"Couldn't find any page with nodeId={0}. This is most likely caused by the page not being published.",
|
||||
() => id);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// there was no route in the cache - create a route
|
||||
var node = umbracoContext.ContentCache.GetById(id);
|
||||
if (node == null)
|
||||
{
|
||||
LogHelper.Warn<DefaultUrlProvider>(
|
||||
"Couldn't find any page with nodeId={0}. This is most likely caused by the page not being published.",
|
||||
() => id);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// walk up from that node until we hit a node with a domain,
|
||||
// or we reach the content root, collecting urls in the way
|
||||
var pathParts = new List<string>();
|
||||
var n = node;
|
||||
domainUri = DomainHelper.DomainForNode(n.Id, current);
|
||||
while (domainUri == null && n != null) // n is null at root
|
||||
{
|
||||
// get the url
|
||||
var urlName = n.UrlName;
|
||||
pathParts.Add(urlName);
|
||||
|
||||
// move to parent node
|
||||
n = n.Parent;
|
||||
domainUri = n == null ? null : DomainHelper.DomainForNode(n.Id, current);
|
||||
}
|
||||
|
||||
// no domain, respect HideTopLevelNodeFromPath for legacy purposes
|
||||
if (domainUri == null && global::umbraco.GlobalSettings.HideTopLevelNodeFromPath)
|
||||
ApplyHideTopLevelNodeFromPath(umbracoContext, node, pathParts);
|
||||
|
||||
// assemble the route
|
||||
pathParts.Reverse();
|
||||
path = "/" + string.Join("/", pathParts); // will be "/" or "/foo" or "/foo/bar" etc
|
||||
route = (n == null ? "" : n.Id.ToString()) + path;
|
||||
|
||||
// do not store if previewing
|
||||
if (!umbracoContext.InPreviewMode)
|
||||
umbracoContext.RoutingContext.RoutesCache.Store(id, route);
|
||||
}
|
||||
// extract domainUri and path
|
||||
// route is /<path> or <domainRootId>/<path>
|
||||
var pos = route.IndexOf('/');
|
||||
var path = pos == 0 ? route : route.Substring(pos);
|
||||
var domainUri = pos == 0 ? null : DomainHelper.DomainForNode(int.Parse(route.Substring(0, pos)), current);
|
||||
|
||||
// assemble the url from domainUri (maybe null) and path
|
||||
return AssembleUrl(domainUri, path, current, mode).ToString();
|
||||
@@ -116,64 +72,22 @@ namespace Umbraco.Web.Routing
|
||||
/// </remarks>
|
||||
public virtual IEnumerable<string> GetOtherUrls(UmbracoContext umbracoContext, int id, Uri current)
|
||||
{
|
||||
string path;
|
||||
IEnumerable<DomainAndUri> domainUris;
|
||||
// will not use cache if previewing
|
||||
var route = umbracoContext.ContentCache.GetRouteById(id);
|
||||
|
||||
// will not read cache if previewing!
|
||||
var route = umbracoContext.InPreviewMode
|
||||
? null
|
||||
: umbracoContext.RoutingContext.RoutesCache.GetRoute(id);
|
||||
|
||||
if (!string.IsNullOrEmpty(route))
|
||||
if (string.IsNullOrWhiteSpace(route))
|
||||
{
|
||||
// there was a route in the cache - extract domainUri and path
|
||||
// route is /<path> or <domainRootId>/<path>
|
||||
int pos = route.IndexOf('/');
|
||||
path = pos == 0 ? route : route.Substring(pos);
|
||||
domainUris = pos == 0 ? null : DomainHelper.DomainsForNode(int.Parse(route.Substring(0, pos)), current);
|
||||
LogHelper.Warn<DefaultUrlProvider>(
|
||||
"Couldn't find any page with nodeId={0}. This is most likely caused by the page not being published.",
|
||||
() => id);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// there was no route in the cache - create a route
|
||||
var node = umbracoContext.ContentCache.GetById(id);
|
||||
if (node == null)
|
||||
{
|
||||
LogHelper.Warn<DefaultUrlProvider>(
|
||||
"Couldn't find any page with nodeId={0}. This is most likely caused by the page not being published.",
|
||||
() => id);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// walk up from that node until we hit a node with domains,
|
||||
// or we reach the content root, collecting urls in the way
|
||||
var pathParts = new List<string>();
|
||||
var n = node;
|
||||
domainUris = DomainHelper.DomainsForNode(n.Id, current);
|
||||
while (domainUris == null && n != null) // n is null at root
|
||||
{
|
||||
// get the url
|
||||
var urlName = node.UrlName;
|
||||
pathParts.Add(urlName);
|
||||
|
||||
// move to parent node
|
||||
n = n.Parent;
|
||||
domainUris = n == null ? null : DomainHelper.DomainsForNode(n.Id, current);
|
||||
}
|
||||
|
||||
// no domain, respect HideTopLevelNodeFromPath for legacy purposes
|
||||
if (domainUris == null && global::umbraco.GlobalSettings.HideTopLevelNodeFromPath)
|
||||
ApplyHideTopLevelNodeFromPath(umbracoContext, node, pathParts);
|
||||
|
||||
// assemble the route
|
||||
pathParts.Reverse();
|
||||
path = "/" + string.Join("/", pathParts); // will be "/" or "/foo" or "/foo/bar" etc
|
||||
route = (n == null ? "" : n.Id.ToString()) + path;
|
||||
|
||||
// do not store if previewing
|
||||
if (!umbracoContext.InPreviewMode)
|
||||
umbracoContext.RoutingContext.RoutesCache.Store(id, route);
|
||||
}
|
||||
// extract domainUri and path
|
||||
// route is /<path> or <domainRootId>/<path>
|
||||
var pos = route.IndexOf('/');
|
||||
var path = pos == 0 ? route : route.Substring(pos);
|
||||
var domainUris = pos == 0 ? null : DomainHelper.DomainsForNode(int.Parse(route.Substring(0, pos)), current);
|
||||
|
||||
// assemble the alternate urls from domainUris (maybe empty) and path
|
||||
return AssembleUrls(domainUris, path).Select(uri => uri.ToString());
|
||||
@@ -271,28 +185,6 @@ namespace Umbraco.Web.Routing
|
||||
return uris.Select(UriUtility.UriFromUmbraco);
|
||||
}
|
||||
|
||||
static void ApplyHideTopLevelNodeFromPath(UmbracoContext umbracoContext, Core.Models.IPublishedContent node, IList<string> pathParts)
|
||||
{
|
||||
// in theory if hideTopLevelNodeFromPath is true, then there should be only once
|
||||
// top-level node, or else domains should be assigned. but for backward compatibility
|
||||
// we add this check - we look for the document matching "/" and if it's not us, then
|
||||
// we do not hide the top level path
|
||||
// it has to be taken care of in IPublishedContentStore.GetDocumentByRoute too so if
|
||||
// "/foo" fails (looking for "/*/foo") we try also "/foo".
|
||||
// this does not make much sense anyway esp. if both "/foo/" and "/bar/foo" exist, but
|
||||
// that's the way it works pre-4.10 and we try to be backward compat for the time being
|
||||
if (node.Parent == null)
|
||||
{
|
||||
var rootNode = umbracoContext.ContentCache.GetByRoute("/", true);
|
||||
if (rootNode.Id == node.Id) // remove only if we're the default node
|
||||
pathParts.RemoveAt(pathParts.Count - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pathParts.RemoveAt(pathParts.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,16 @@ namespace Umbraco.Web.Routing
|
||||
return domainAndUri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a specified node has domains.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identifier.</param>
|
||||
/// <returns>True if the node has domains, else false.</returns>
|
||||
internal static bool NodeHasDomains(int nodeId)
|
||||
{
|
||||
return nodeId > 0 && GetNodeDomains(nodeId, false).Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the domains for the specified node, if any, that match a specified uri.
|
||||
/// </summary>
|
||||
|
||||
@@ -11,6 +11,6 @@ namespace Umbraco.Web.Routing
|
||||
/// <param name="contentRequest">The <c>PublishedContentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
/// <remarks>Optionally, can also assign the template or anything else on the document request, although that is not required.</remarks>
|
||||
bool TryFindDocument(PublishedContentRequest contentRequest);
|
||||
bool TryFindContent(PublishedContentRequest contentRequest);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a bi-directional cache that binds node identifiers and routes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The cache is used both for inbound (map a route to a node) and outbound (map a node to a url).</para>
|
||||
/// <para>A route is <c>[rootId]/path/to/node</c> where <c>rootId</c> is the id of the node holding an Umbraco domain, or -1.</para>
|
||||
/// </remarks>
|
||||
internal interface IRoutesCache
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores a route for a node.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identified.</param>
|
||||
/// <param name="route">The route.</param>
|
||||
void Store(int nodeId, string route);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a route for a node.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identifier.</param>
|
||||
/// <returns>The route for the node, else null.</returns>
|
||||
string GetRoute(int nodeId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a node for a route.
|
||||
/// </summary>
|
||||
/// <param name="route">The route.</param>
|
||||
/// <returns>The node identified for the route, else zero.</returns>
|
||||
int GetNodeId(string route);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the route for a node.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identifier.</param>
|
||||
void ClearNode(int nodeId);
|
||||
|
||||
/// <summary>
|
||||
/// Clears all routes.
|
||||
/// </summary>
|
||||
void Clear();
|
||||
}
|
||||
}
|
||||
@@ -335,7 +335,7 @@ namespace Umbraco.Web.Routing
|
||||
{
|
||||
if (_routingContext.PublishedContentFinders == null)
|
||||
throw new InvalidOperationException("There is no finder collection.");
|
||||
_routingContext.PublishedContentFinders.Any(finder => finder.TryFindDocument(_pcr));
|
||||
_routingContext.PublishedContentFinders.Any(finder => finder.TryFindContent(_pcr));
|
||||
}
|
||||
|
||||
// indicate that the published content (if any) we have at the moment is the
|
||||
@@ -369,7 +369,7 @@ namespace Umbraco.Web.Routing
|
||||
|
||||
// if it fails then give up, there isn't much more that we can do
|
||||
var lastChance = _routingContext.PublishedContentLastChanceFinder;
|
||||
if (lastChance == null || !lastChance.TryFindDocument(_pcr))
|
||||
if (lastChance == null || !lastChance.TryFindContent(_pcr))
|
||||
{
|
||||
LogHelper.Debug<PublishedContentRequestEngine>("{0}Failed to find a document, give up", () => tracePrefix);
|
||||
break;
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
using System;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolves the <see cref="IRoutesCache"/> implementation.
|
||||
/// </summary>
|
||||
internal sealed class RoutesCacheResolver : SingleObjectResolverBase<RoutesCacheResolver, IRoutesCache>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RoutesCacheResolver"/> class with an <see cref="IRoutesCache"/> implementation.
|
||||
/// </summary>
|
||||
/// <param name="routesCache">The <see cref="IRoutesCache"/> implementation.</param>
|
||||
internal RoutesCacheResolver(IRoutesCache routesCache)
|
||||
: base(routesCache)
|
||||
{ }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Can be used by developers at runtime to set their IRoutesCache at app startup
|
||||
/// </summary>
|
||||
/// <param name="routesCache"></param>
|
||||
public void SetRoutesCache(IRoutesCache routesCache)
|
||||
{
|
||||
Value = routesCache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IRoutesCache"/> implementation.
|
||||
/// </summary>
|
||||
public IRoutesCache RoutesCache
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,19 +16,16 @@ namespace Umbraco.Web.Routing
|
||||
/// <param name="contentFinders">The document lookups resolver.</param>
|
||||
/// <param name="contentLastChanceFinder"> </param>
|
||||
/// <param name="urlProvider">The nice urls provider.</param>
|
||||
/// <param name="routesCache">The routes cache.</param>
|
||||
internal RoutingContext(
|
||||
UmbracoContext umbracoContext,
|
||||
IEnumerable<IContentFinder> contentFinders,
|
||||
IContentFinder contentLastChanceFinder,
|
||||
UrlProvider urlProvider,
|
||||
IRoutesCache routesCache)
|
||||
UrlProvider urlProvider)
|
||||
{
|
||||
UmbracoContext = umbracoContext;
|
||||
PublishedContentFinders = contentFinders;
|
||||
PublishedContentLastChanceFinder = contentLastChanceFinder;
|
||||
UrlProvider = urlProvider;
|
||||
RoutesCache = routesCache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -50,10 +47,5 @@ namespace Umbraco.Web.Routing
|
||||
/// Gets the urls provider.
|
||||
/// </summary>
|
||||
internal UrlProvider UrlProvider { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IRoutesCache"/>
|
||||
/// </summary>
|
||||
internal IRoutesCache RoutesCache { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -330,6 +330,7 @@
|
||||
<Compile Include="Mvc\MemberAuthorizeAttribute.cs" />
|
||||
<Compile Include="Mvc\ControllerFactoryExtensions.cs" />
|
||||
<Compile Include="Mvc\SurfaceRouteHandler.cs" />
|
||||
<Compile Include="PublishedCache\LegacyXmlCache\RoutesCache.cs" />
|
||||
<Compile Include="Routing\UrlProviderMode.cs" />
|
||||
<Compile Include="Search\ExamineIndexerModel.cs" />
|
||||
<Compile Include="Search\LuceneIndexerExtensions.cs" />
|
||||
@@ -595,9 +596,6 @@
|
||||
<Compile Include="Routing\ContentFinderResolver.cs" />
|
||||
<Compile Include="Routing\PublishedContentRequest.cs" />
|
||||
<Compile Include="Routing\IContentFinder.cs" />
|
||||
<Compile Include="Routing\IRoutesCache.cs" />
|
||||
<Compile Include="Routing\DefaultRoutesCache.cs" />
|
||||
<Compile Include="Routing\RoutesCacheResolver.cs" />
|
||||
<Compile Include="Routing\RoutingContext.cs" />
|
||||
<Compile Include="umbraco.presentation\EnsureSystemPathsApplicationStartupHandler.cs" />
|
||||
<Compile Include="umbraco.presentation\install\steps\Definitions\LegacyClasses.cs">
|
||||
|
||||
@@ -98,8 +98,7 @@ namespace Umbraco.Web
|
||||
umbracoContext,
|
||||
ContentFinderResolver.Current.Finders,
|
||||
ContentLastChanceFinderResolver.Current.Finder,
|
||||
urlProvider,
|
||||
RoutesCacheResolver.Current.RoutesCache);
|
||||
urlProvider);
|
||||
|
||||
//assign the routing context back
|
||||
umbracoContext.RoutingContext = routingContext;
|
||||
|
||||
@@ -313,7 +313,7 @@ namespace Umbraco.Web
|
||||
|
||||
SiteDomainHelperResolver.Current = new SiteDomainHelperResolver(new SiteDomainHelper());
|
||||
|
||||
RoutesCacheResolver.Current = new RoutesCacheResolver(new DefaultRoutesCache(_isForTesting == false));
|
||||
PublishedContentCache.UnitTesting = _isForTesting;
|
||||
|
||||
ThumbnailProvidersResolver.Current = new ThumbnailProvidersResolver(
|
||||
PluginManager.Current.ResolveThumbnailProviders());
|
||||
@@ -323,7 +323,6 @@ namespace Umbraco.Web
|
||||
|
||||
CultureDictionaryFactoryResolver.Current = new CultureDictionaryFactoryResolver(
|
||||
new DefaultCultureDictionaryFactory());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user