This commit is contained in:
shannon@ShandemVaio
2012-07-26 22:53:58 +06:00
32 changed files with 974 additions and 444 deletions

View File

@@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Umbraco.Core.Resolving
{
public class ManyWeightedResolved<TResolved>
{
List<TResolved> _resolved = new List<TResolved>();
Dictionary<Type, int> _weights = new Dictionary<Type, int>();
public ManyWeightedResolved()
{
Resolution.Frozen += (sender, e) =>
{
_resolved = _resolved.OrderBy(r => _weights[r.GetType()]).ToList();
_weights = null;
};
}
public ManyWeightedResolved(IEnumerable<TResolved> resolved)
: this()
{
_resolved.AddRange(resolved);
foreach (var type in _resolved.Select(r => r.GetType()))
_weights.Add(type, ResolutionWeightAttribute.ReadWeight(type));
}
public IEnumerable<TResolved> Values
{
get { return _resolved; }
}
#region Manage collection
public void Add(TResolved value)
{
Resolution.EnsureNotFrozen();
var type = value.GetType();
EnsureNotExists(type);
_resolved.Add(value);
_weights[type] = ResolutionWeightAttribute.ReadWeight(type);
}
public void Add(TResolved value, int weight)
{
Resolution.EnsureNotFrozen();
var type = value.GetType();
EnsureNotExists(type);
_resolved.Add(value);
_weights[type] = weight;
}
public void AddRange(IEnumerable<TResolved> values)
{
Resolution.EnsureNotFrozen();
foreach (var value in values)
{
var type = value.GetType();
EnsureNotExists(type);
_resolved.Add(value);
_weights[type] = ResolutionWeightAttribute.ReadWeight(type);
}
}
//public void SetWeight(TResolved value, int weight)
//{
// Resolution.EnsureNotFrozen();
// var type = value.GetType();
// EnsureExists(type);
// _weights[type] = weight;
//}
public void SetWeight<TResolving>(int weight)
{
Resolution.EnsureNotFrozen();
var type = typeof(TResolving);
EnsureExists(type);
_weights[type] = weight;
}
//public int GetWeight(TResolved value)
//{
// var type = value.GetType();
// EnsureExists(type);
// return _weights[value.GetType()];
//}
public int GetWeight<TResolving>()
{
var type = typeof(TResolving);
EnsureExists(type);
return _weights[type];
}
//public void Remove(TResolved value)
//{
// Resolution.EnsureNotFrozen();
// var type = value.GetType();
// var remove = _resolved.SingleOrDefault(r => r.GetType() == type);
// if (remove != null)
// {
// _resolved.Remove(remove);
// _weights.Remove(remove.GetType());
// }
//}
public void Remove<TResolving>()
{
Resolution.EnsureNotFrozen();
var type = typeof(TResolving);
var remove = _resolved.SingleOrDefault(r => r.GetType() == type);
if (remove != null)
{
_resolved.Remove(remove);
_weights.Remove(remove.GetType());
}
}
public void Clear()
{
Resolution.EnsureNotFrozen();
_resolved = new List<TResolved>();
_weights = new Dictionary<Type, int>();
}
#endregion
#region Utilities
public bool Exists(Type type)
{
return _resolved.Any(r => r.GetType() == type);
}
void EnsureExists(Type type)
{
if (!Exists(type))
throw new InvalidOperationException("There is not value of that type in the collection.");
}
void EnsureNotExists(Type type)
{
if (Exists(type))
throw new InvalidOperationException("A value of that type already exists in the collection.");
}
#endregion
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Umbraco.Core.Resolving
{
public abstract class ManyWeightedResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
{
ManyWeightedResolved<TResolved> _resolved;
protected ManyWeightedResolverBase()
{
_resolved = new ManyWeightedResolved<TResolved>();
}
protected ManyWeightedResolverBase(IEnumerable<TResolved> values)
{
_resolved = new ManyWeightedResolved<TResolved>(values);
}
protected IEnumerable<TResolved> Values
{
get { return _resolved.Values; }
}
#region Manage collection
public void Add(TResolved value)
{
_resolved.Add(value);
}
public void Add(TResolved value, int weight)
{
_resolved.Add(value, weight);
}
public void AddRange(IEnumerable<TResolved> values)
{
_resolved.AddRange(values);
}
public void SetWeight<TResolving>(int weight)
{
_resolved.SetWeight<TResolving>(weight);
}
public int GetWeight<TResolving>()
{
return _resolved.GetWeight<TResolving>();
}
public void Remove<TResolving>()
{
_resolved.Remove<TResolving>();
}
public void Clear()
{
_resolved.Clear();
}
#endregion
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Umbraco.Core.Resolving
{
// notes: nothing in Resolving is thread-safe because everything should happen when the app is starting
public class Resolution
{
public static event EventHandler Freezing;
public static event EventHandler Frozen;
public static bool IsFrozen { get; private set; }
public static void EnsureNotFrozen()
{
if (Resolution.IsFrozen)
throw new InvalidOperationException("Resolution is frozen. It is not possible to modify resolvers once resolution is frozen.");
}
public static void Freeze()
{
if (Resolution.IsFrozen)
throw new InvalidOperationException("Resolution is frozen. It is not possible to freeze it again.");
if (Freezing != null)
Freezing(null, null);
IsFrozen = true;
if (Frozen != null)
Frozen(null, null);
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Umbraco.Core.Resolving
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=false)]
public class ResolutionWeightAttribute : Attribute
{
public const int DefaultWeight = 100;
public ResolutionWeightAttribute(int weight)
{
this.Weight = weight;
}
public int Weight { get; private set; }
public static int ReadWeight(Type type)
{
var attr = type.GetCustomAttribute<ResolutionWeightAttribute>(false);
return attr != null ? attr.Weight : DefaultWeight;
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Threading;
namespace Umbraco.Core.Resolving
{
public abstract class ResolverBase<TResolver>
{
static TResolver _resolver;
static readonly ReaderWriterLockSlim ResolversLock = new ReaderWriterLockSlim();
public static TResolver Current
{
get
{
using (new ReadLock(ResolversLock))
{
if (_resolver == null)
throw new InvalidOperationException("Current has not been initialized. You must initialize Current before trying to read it.");
return _resolver;
}
}
set
{
using (new WriteLock(ResolversLock))
{
if (value == null)
throw new ArgumentNullException("value");
if (_resolver != null)
throw new InvalidOperationException("Current has already been initialized. It is not possible to re-initialize Current once it has been initialized.");
_resolver = value;
}
}
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
namespace Umbraco.Core.Resolving
{
public class SingleResolved<TResolved>
{
TResolved _resolved;
bool _canBeNull;
public SingleResolved()
: this(false)
{ }
public SingleResolved(TResolved value)
: this(false)
{
_resolved = value;
}
public SingleResolved(bool canBeNull)
{
_canBeNull = canBeNull;
}
public SingleResolved(TResolved value, bool canBeNull)
{
_resolved = value;
_canBeNull = canBeNull;
}
public TResolved Value
{
get
{
return _resolved;
}
set
{
Resolution.EnsureNotFrozen();
if (!_canBeNull && value == null)
throw new ArgumentNullException("value");
_resolved = value;
}
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
namespace Umbraco.Core.Resolving
{
public abstract class SingleResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
{
TResolved _resolved;
bool _canBeNull;
protected SingleResolverBase()
: this(false)
{ }
protected SingleResolverBase(TResolved value)
: this(false)
{
_resolved = value;
}
protected SingleResolverBase(bool canBeNull)
{
_canBeNull = canBeNull;
}
protected SingleResolverBase(TResolved value, bool canBeNull)
{
_resolved = value;
_canBeNull = canBeNull;
}
protected TResolved Value
{
get
{
return _resolved;
}
set
{
Resolution.EnsureNotFrozen();
if (!_canBeNull && value == null)
throw new ArgumentNullException("value");
_resolved = value;
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;

View File

@@ -48,6 +48,14 @@
<Compile Include="ApplicationContext.cs" />
<Compile Include="ExpressionHelper.cs" />
<Compile Include="LambdaExpressionCacheKey.cs" />
<Compile Include="Resolving\ManyWeightedResolved.cs" />
<Compile Include="Resolving\ManyWeightedResolverBase.cs" />
<Compile Include="Resolving\Resolution.cs" />
<Compile Include="Resolving\ResolutionWeightAttribute.cs" />
<Compile Include="Resolving\ResolverBase.cs" />
<Compile Include="Resolving\SingleResolved.cs" />
<Compile Include="Resolving\SingleResolverBase.cs" />
<Compile Include="TypeExtensions.cs" />
<Compile Include="ReadLock.cs" />
<Compile Include="SystemUtilities.cs" />
<Compile Include="TypeExtensions.cs" />

View File

@@ -1,158 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Umbraco.Core;
using Umbraco.Web.Routing;
using umbraco;
using umbraco.IO;
using umbraco.cms.businesslogic.web;
namespace Umbraco.Web
{
/// <summary>
/// Resolves NiceUrls for a given node id
/// </summary>
internal class NiceUrlResolver
{
public NiceUrlResolver(ContentStore contentStore, UmbracoContext umbracoContext)
{
_umbracoContext = umbracoContext;
_contentStore = contentStore;
}
private readonly UmbracoContext _umbracoContext;
private readonly ContentStore _contentStore;
// note: this could be a parameter...
const string UrlNameProperty = "@urlName";
#region GetNiceUrl
public string GetNiceUrl(int nodeId)
{
return GetNiceUrl(nodeId, _umbracoContext.UmbracoUrl, false);
}
public string GetNiceUrl(int nodeId, Uri current, bool absolute)
{
string path;
Uri domainUri;
// will not read cache if previewing!
var route = _umbracoContext.InPreviewMode
? null
: _umbracoContext.RoutesCache.GetRoute(nodeId);
if (route != null)
{
// route is <id>/<path> eg "-1/", "-1/foo", "123/", "123/foo/bar"...
int pos = route.IndexOf('/');
path = route.Substring(pos);
int id = int.Parse(route.Substring(0, pos)); // will be -1 or 1234
domainUri = id > 0 ? DomainUriAtNode(id, current) : null;
}
else
{
var node = _contentStore.GetNodeById(nodeId);
if (node == null)
return "#"; // legacy wrote to the log here...
var pathParts = new List<string>();
int id = nodeId;
domainUri = DomainUriAtNode(id, current);
while (domainUri == null && id > 0)
{
pathParts.Add(_contentStore.GetNodeProperty(node, UrlNameProperty));
node = _contentStore.GetNodeParent(node);
id = int.Parse(_contentStore.GetNodeProperty(node, "@id")); // will be -1 or 1234
domainUri = id > 0 ? DomainUriAtNode(id, current) : null;
}
// no domain, respect HideTopLevelNodeFromPath for legacy purposes
if (domainUri == null && global::umbraco.GlobalSettings.HideTopLevelNodeFromPath)
pathParts.RemoveAt(pathParts.Count - 1);
pathParts.Reverse();
path = "/" + string.Join("/", pathParts); // will be "/" or "/foo" or "/foo/bar" etc
route = id.ToString() + path;
if (!_umbracoContext.InPreviewMode)
_umbracoContext.RoutesCache.Store(nodeId, route);
}
return AssembleUrl(domainUri, path, current, absolute).ToString();
}
Uri AssembleUrl(Uri domain, string path, Uri current, bool absolute)
{
Uri uri;
if (domain == null)
{
// no domain was found : return a relative url, add vdir if any
uri = new Uri(global::umbraco.IO.SystemDirectories.Root + path, UriKind.Relative);
}
else
{
// a domain was found : return an absolute or relative url
// cannot handle vdir, has to be in domain uri
if (!absolute && current != null && domain.GetLeftPart(UriPartial.Authority) == current.GetLeftPart(UriPartial.Authority))
uri = new Uri(domain.AbsolutePath.TrimEnd('/') + path, UriKind.Relative); // relative
else
uri = new Uri(domain.GetLeftPart(UriPartial.Path).TrimEnd('/') + path); // absolute
}
return UriFromUmbraco(uri);
}
Uri DomainUriAtNode(int nodeId, Uri current)
{
// be safe
if (nodeId <= 0)
return null;
// apply filter on domains defined on that node
var domainAndUri = Domains.ApplicableDomains(Domain.GetDomainsById(nodeId), current, true);
return domainAndUri == null ? null : domainAndUri.Uri;
}
#endregion
#region Map public urls to/from umbraco urls
// fixme - what about vdir?
// path = path.Substring(UriUtility.AppVirtualPathPrefix.Length); // remove virtual directory
public static Uri UriFromUmbraco(Uri uri)
{
var path = uri.GetSafeAbsolutePath();
if (path == "/")
return uri;
if (!global::umbraco.GlobalSettings.UseDirectoryUrls)
path += ".aspx";
else if (global::umbraco.UmbracoSettings.AddTrailingSlash)
path += "/";
return uri.Rewrite(path);
}
public static Uri UriToUmbraco(Uri uri)
{
var path = uri.GetSafeAbsolutePath();
path = path.ToLower();
if (path != "/")
path = path.TrimEnd('/');
if (path.EndsWith(".aspx"))
path = path.Substring(0, path.Length - ".aspx".Length);
return uri.Rewrite(path);
}
#endregion
}
}

View File

@@ -13,7 +13,7 @@ namespace Umbraco.Web
public static class PluginResolverExtensions
{
private static volatile IEnumerable<IRequestDocumentResolver> _lookups;
private static volatile IEnumerable<IDocumentLookup> _lookups;
private static readonly object Locker = new object();
/// <summary>
@@ -21,7 +21,7 @@ namespace Umbraco.Web
/// </summary>
/// <param name="plugins"></param>
/// <returns></returns>
internal static IEnumerable<IRequestDocumentResolver> ResolveLookups(this PluginResolver plugins)
internal static IEnumerable<IDocumentLookup> ResolveLookups(this PluginResolver plugins)
{
if (_lookups == null)
{
@@ -29,14 +29,13 @@ namespace Umbraco.Web
{
if (_lookups == null)
{
var typeFinder = new TypeFinder2();
var lookupTypes = typeFinder.FindClassesOfType<IRequestDocumentResolver>();
var lookups = new List<IRequestDocumentResolver>();
var lookupTypes = TypeFinder.FindClassesOfType<IDocumentLookup>();
var lookups = new List<IDocumentLookup>();
foreach (var l in lookupTypes)
{
try
{
var typeInstance = Activator.CreateInstance(l) as IRequestDocumentResolver;
var typeInstance = Activator.CreateInstance(l) as IDocumentLookup;
lookups.Add(typeInstance);
}
catch (Exception ex)

View File

@@ -6,7 +6,7 @@ using Umbraco.Core;
namespace Umbraco.Web.Routing
{
/// <summary>
/// The default implementation of IRoutesCache
/// Provides a default implementation of <see cref="IRoutesCache"/>.
/// </summary>
internal class DefaultRoutesCache : IRoutesCache
{
@@ -14,23 +14,31 @@ namespace Umbraco.Web.Routing
private Dictionary<int, string> _routes;
private Dictionary<string, int> _nodeIds;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultRoutesCache"/> class.
/// </summary>
public DefaultRoutesCache()
{
Clear();
// here we should register handlers to clear the cache when content changes
// at the moment this is done by library, which clears everything when content changed
//
// but really, we should do some partial refreshes!
// otherwise, we could even cache 404 errors...
//
// these are the two events used by library in legacy code...
// is it enough?
//FIXME:
//
// here we must register handlers to clear the cache when content changes
// this was done by presentation.library, which cleared everything when content changed
// but really, we should do some partial refreshes
// these are the two events that were used by presentation.library
// are they enough?
global::umbraco.content.AfterRefreshContent += (sender, e) => Clear();
global::umbraco.content.AfterUpdateDocumentCache += (sender, e) => Clear();
}
/// <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)
{
using (new WriteLock(_lock))
@@ -40,6 +48,11 @@ namespace Umbraco.Web.Routing
}
}
/// <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)
{
lock (new ReadLock(_lock))
@@ -48,6 +61,11 @@ namespace Umbraco.Web.Routing
}
}
/// <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)
{
using (new ReadLock(_lock))
@@ -56,6 +74,10 @@ namespace Umbraco.Web.Routing
}
}
/// <summary>
/// Clears the route for a node.
/// </summary>
/// <param name="nodeId">The node identifier.</param>
public void ClearNode(int nodeId)
{
using (var lck = new UpgradeableReadLock(_lock))
@@ -69,6 +91,9 @@ namespace Umbraco.Web.Routing
}
}
/// <summary>
/// Clears all routes.
/// </summary>
public void Clear()
{
using (new WriteLock(_lock))

View File

@@ -140,22 +140,22 @@ namespace Umbraco.Web.Routing
#endregion
#region Resolve
#region Lookup
/// <summary>
/// Determines the site root (if any) matching the http request.
/// </summary>
/// <returns>A value indicating whether a domain was found.</returns>
public bool ResolveDomain()
public bool LookupDomain()
{
const string tracePrefix = "ResolveDomain: ";
const string tracePrefix = "LookupDomain: ";
// note - we are not handling schemes nor ports here.
Trace.TraceInformation("{0}Uri=\"{1}\"", tracePrefix, this.Uri);
// try to find a domain matching the current request
var domainAndUri = Domains.ApplicableDomains(Domain.GetDomains(), RoutingContext.UmbracoContext.UmbracoUrl, false);
var domainAndUri = Domains.DomainMatch(Domain.GetDomains(), RoutingContext.UmbracoContext.UmbracoUrl, false);
// handle domain
if (domainAndUri != null)
@@ -193,17 +193,17 @@ namespace Umbraco.Web.Routing
/// Determines the Umbraco document (if any) matching the http request.
/// </summary>
/// <returns>A value indicating whether a document and template nave been found.</returns>
public bool ResolveDocument()
public bool LookupDocument()
{
const string tracePrefix = "ResolveDocument: ";
const string tracePrefix = "LookupDocument: ";
Trace.TraceInformation("{0}Path=\"{1}\"", tracePrefix, this.Uri.AbsolutePath);
// look for the document
// the first successful resolver, if any, will set this.Node, and may also set this.Template
// some lookups may implement caching
Trace.TraceInformation("{0}Begin resolvers", tracePrefix);
var resolvers = RoutingContext.RouteLookups.GetLookups();
resolvers.Any(resolver => resolver.TrySetDocument(this));
var lookups = RoutingContext.DocumentLookupsResolver.DocumentLookups;
lookups.Any(lookup => lookup.TrySetDocument(this));
Trace.TraceInformation("{0}End resolvers, {1}", tracePrefix, (this.HasNode ? "a document was found" : "no document was found"));
// fixme - not handling umbracoRedirect
@@ -211,7 +211,7 @@ namespace Umbraco.Web.Routing
// so after ResolveDocument2() => docreq.IsRedirect => handled by the module!
// handle not-found, redirects, access, template
ResolveDocument2();
LookupDocument2();
// handle umbracoRedirect (moved from umbraco.page)
FollowRedirect();
@@ -224,9 +224,9 @@ namespace Umbraco.Web.Routing
/// Performs the document resolution second pass.
/// </summary>
/// <remarks>The second pass consists in handling "not found", internal redirects, access validation, and template.</remarks>
void ResolveDocument2()
void LookupDocument2()
{
const string tracePrefix = "ResolveDocument2: ";
const string tracePrefix = "LookupDocument2: ";
// handle "not found", follow internal redirects, validate access, template
// because these might loop, we have to have some sort of infinite loop detection
@@ -240,10 +240,11 @@ namespace Umbraco.Web.Routing
if (!this.HasNode)
{
this.Is404 = true;
Trace.TraceInformation("{0}No document, try notFound lookup", tracePrefix);
Trace.TraceInformation("{0}No document, try last chance lookup", tracePrefix);
// if it fails then give up, there isn't much more that we can do
if (RoutingContext.LookupNotFound == null || !RoutingContext.LookupNotFound.TrySetDocument(this))
var lastChance = RoutingContext.DocumentLookupsResolver.DocumentLastChanceLookup;
if (lastChance == null || !lastChance.TrySetDocument(this))
{
Trace.TraceInformation("{0}Failed to find a document, give up", tracePrefix);
break;
@@ -266,7 +267,7 @@ namespace Umbraco.Web.Routing
// resolve template
if (this.HasNode)
ResolveTemplate();
LookupTemplate();
// loop while we don't have page, ie the redirect or access
// got us to nowhere and now we need to run the notFoundLookup again
@@ -383,9 +384,9 @@ namespace Umbraco.Web.Routing
/// <summary>
/// Resolves a template for the current node.
/// </summary>
void ResolveTemplate()
void LookupTemplate()
{
const string tracePrefix = "ResolveTemplate: ";
const string tracePrefix = "LookupTemplate: ";
if (this.Node == null)
throw new InvalidOperationException("There is no node.");
@@ -446,7 +447,7 @@ namespace Umbraco.Web.Routing
redirectId = -1;
string redirectUrl = "#";
if (redirectId > 0)
redirectUrl = RoutingContext.NiceUrlResolver.GetNiceUrl(redirectId);
redirectUrl = RoutingContext.NiceUrlProvider.GetNiceUrl(redirectId);
if (redirectUrl != "#")
this.RedirectUrl = redirectUrl;
}

View File

@@ -8,20 +8,48 @@ using umbraco.cms.businesslogic.web;
namespace Umbraco.Web.Routing
{
/// <summary>
/// Provides utilities to handle domains.
/// </summary>
public class Domains
{
/// <summary>
/// Represents an Umbraco domain and its normalized uri.
/// </summary>
/// <remarks>
/// <para>In Umbraco it is valid to create domains with name such as <c>example.com</c>, <c>https://www.example.com</c>, <c>example.com/foo/</c>.</para>
/// <para>The normalized uri of a domain begins with a scheme and ends with no slash, eg <c>http://example.com/</c>, <c>https://www.example.com/</c>, <c>http://example.com/foo/</c>.</para>
/// </remarks>
public class DomainAndUri
{
/// <summary>
/// The Umbraco domain.
/// </summary>
public Domain Domain;
/// <summary>
/// The normalized uri of the domain.
/// </summary>
public Uri Uri;
/// <summary>
/// Gets a string that represents the <see cref="DomainAndUri"/> instance.
/// </summary>
/// <returns>A string that represents the current <see cref="DomainAndUri"/> instance.</returns>
public override string ToString()
{
return string.Format("{{ \"{0}\", \"{1}\" }}", Domain.Name, Uri);
}
}
public static DomainAndUri ApplicableDomains(IEnumerable<Domain> domains, Uri current, bool defaultToFirst)
/// <summary>
/// Finds the domain that best matches the current uri, into an enumeration of domains.
/// </summary>
/// <param name="domains">The enumeration of Umbraco domains.</param>
/// <param name="current">The uri of the current request, or null.</param>
/// <param name="defaultToFirst">A value indicating whether to return the first domain of the list when no domain matches.</param>
/// <returns>The domain and its normalized uri, that best matches the current uri, else the first domain (if <c>defaultToFirst</c> is <c>true</c>), else null.</returns>
public static DomainAndUri DomainMatch(IEnumerable<Domain> domains, Uri current, bool defaultToFirst)
{
if (!domains.Any())
return null;
@@ -57,6 +85,29 @@ namespace Umbraco.Web.Routing
return domainAndUri;
}
/// <summary>
/// Gets an enumeration of <see cref="DomainAndUri"/> matching an enumeration of Umbraco domains.
/// </summary>
/// <param name="domains">The enumeration of Umbraco domains.</param>
/// <param name="current">The uri of the current request, or null.</param>
/// <returns>The enumeration of <see cref="DomainAndUri"/> matching the enumeration of Umbraco domains.</returns>
public static IEnumerable<DomainAndUri> DomainMatches(IEnumerable<Domain> domains, Uri current)
{
var scheme = current == null ? Uri.UriSchemeHttp : current.Scheme;
var domainsAndUris = domains
.Select(d => new { Domain = d, UriString = UriUtility.TrimPathEndSlash(UriUtility.StartWithScheme(d.Name, scheme)) })
.OrderByDescending(t => t.UriString)
.Select(t => new DomainAndUri { Domain = t.Domain, Uri = new Uri(t.UriString) });
return domainsAndUris;
}
/// <summary>
/// Returns the part of a path relative to the uri of a domain.
/// </summary>
/// <param name="domainUri">The normalized uri of the domain.</param>
/// <param name="path">The full path of the uri.</param>
/// <returns>The path part relative to the uri of the domain.</returns>
/// <remarks>Eg the relative part of <c>/foo/bar/nil</c> to domain <c>example.com/foo</c> is <c>/bar/nil</c>.</remarks>
public static string PathRelativeToDomain(Uri domainUri, string path)
{
return path.Substring(domainUri.AbsolutePath.Length).EnsureStartsWith('/');

View File

@@ -1,11 +1,44 @@
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();
}
}

View File

@@ -0,0 +1,260 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Umbraco.Core;
using Umbraco.Web.Routing;
using umbraco;
using umbraco.IO;
using umbraco.cms.businesslogic.web;
namespace Umbraco.Web.Routing
{
/// <summary>
/// Provides nice urls for a nodes.
/// </summary>
internal class NiceUrlProvider
{
/// <summary>
/// Initializes a new instance of the <see cref="NiceUrlProvider"/> class.
/// </summary>
/// <param name="contentStore">The content store.</param>
/// <param name="umbracoContext">The Umbraco context.</param>
public NiceUrlProvider(ContentStore contentStore, UmbracoContext umbracoContext)
{
_umbracoContext = umbracoContext;
_contentStore = contentStore;
}
private readonly UmbracoContext _umbracoContext;
private readonly ContentStore _contentStore;
// note: this could be a parameter...
const string UrlNameProperty = "@urlName";
#region GetNiceUrl
/// <summary>
/// Gets the nice url of a node.
/// </summary>
/// <param name="nodeId">The node id.</param>
/// <returns>The nice url for the node.</returns>
/// <remarks>The url is absolute or relative depending on the current url.</remarks>
public string GetNiceUrl(int nodeId)
{
return GetNiceUrl(nodeId, _umbracoContext.UmbracoUrl, false);
}
/// <summary>
/// Gets the nice url of a node.
/// </summary>
/// <param name="nodeId">The node id.</param>
/// <param name="current">The current url.</param>
/// <param name="absolute">A value indicating whether the url should be absolute in any case.</param>
/// <returns>The nice url for the node.</returns>
/// <remarks>The url is absolute or relative depending on the current url, unless absolute is true, and then it is always absolute.</remarks>
public string GetNiceUrl(int nodeId, Uri current, bool absolute)
{
string path;
Uri domainUri;
// will not read cache if previewing!
var route = _umbracoContext.InPreviewMode
? null
: _umbracoContext.RoutesCache.GetRoute(nodeId);
if (route != null)
{
// route is <id>/<path> eg "-1/", "-1/foo", "123/", "123/foo/bar"...
int pos = route.IndexOf('/');
path = route.Substring(pos);
int id = int.Parse(route.Substring(0, pos)); // will be -1 or 1234
domainUri = id > 0 ? DomainUriAtNode(id, current) : null;
}
else
{
var node = _contentStore.GetNodeById(nodeId);
if (node == null)
return "#"; // legacy wrote to the log here...
var pathParts = new List<string>();
int id = nodeId;
domainUri = DomainUriAtNode(id, current);
while (domainUri == null && id > 0)
{
pathParts.Add(_contentStore.GetNodeProperty(node, UrlNameProperty));
node = _contentStore.GetNodeParent(node);
id = int.Parse(_contentStore.GetNodeProperty(node, "@id")); // will be -1 or 1234
domainUri = id > 0 ? DomainUriAtNode(id, current) : null;
}
// no domain, respect HideTopLevelNodeFromPath for legacy purposes
if (domainUri == null && global::umbraco.GlobalSettings.HideTopLevelNodeFromPath)
pathParts.RemoveAt(pathParts.Count - 1);
pathParts.Reverse();
path = "/" + string.Join("/", pathParts); // will be "/" or "/foo" or "/foo/bar" etc
route = id.ToString() + path;
if (!_umbracoContext.InPreviewMode)
_umbracoContext.RoutesCache.Store(nodeId, route);
}
return AssembleUrl(domainUri, path, current, absolute).ToString();
}
/// <summary>
/// Gets the nice urls of a node.
/// </summary>
/// <param name="nodeId">The node id.</param>
/// <param name="current">The current url.</param>
/// <returns>An enumeration of all valid urls for the node.</returns>
/// <remarks>The urls are absolute. A node can have more than one url if more than one domain is defined.</remarks>
public IEnumerable<string> GetNiceUrls(int nodeId, Uri current)
{
// this is for editContent.aspx which had its own, highly buggy, implementation of NiceUrl...
//TODO: finalize & test implementation then replace in editContent.aspx
string path;
IEnumerable<Uri> domainUris;
// will not read cache if previewing!
var route = _umbracoContext.InPreviewMode
? null
: _umbracoContext.RoutesCache.GetRoute(nodeId);
if (route != null)
{
// route is <id>/<path> eg "-1/", "-1/foo", "123/", "123/foo/bar"...
int pos = route.IndexOf('/');
path = route.Substring(pos);
int id = int.Parse(route.Substring(0, pos)); // will be -1 or 1234
domainUris = id > 0 ? DomainUrisAtNode(id, current) : new Uri[] { };
}
else
{
var node = _contentStore.GetNodeById(nodeId);
if (node == null)
return new string[] { "#" }; // legacy wrote to the log here...
var pathParts = new List<string>();
int id = nodeId;
domainUris = DomainUrisAtNode(id, current);
while (!domainUris.Any() && id > 0)
{
pathParts.Add(_contentStore.GetNodeProperty(node, UrlNameProperty));
node = _contentStore.GetNodeParent(node);
id = int.Parse(_contentStore.GetNodeProperty(node, "@id")); // will be -1 or 1234
domainUris = id > 0 ? DomainUrisAtNode(id, current) : new Uri[] { };
}
// no domain, respect HideTopLevelNodeFromPath for legacy purposes
if (!domainUris.Any() && global::umbraco.GlobalSettings.HideTopLevelNodeFromPath)
pathParts.RemoveAt(pathParts.Count - 1);
pathParts.Reverse();
path = "/" + string.Join("/", pathParts); // will be "/" or "/foo" or "/foo/bar" etc
route = id.ToString() + path;
if (!_umbracoContext.InPreviewMode)
_umbracoContext.RoutesCache.Store(nodeId, route);
}
return AssembleUrls(domainUris, path, current).Select(uri => uri.ToString());
}
Uri AssembleUrl(Uri domainUri, string path, Uri current, bool absolute)
{
Uri uri;
if (domainUri == null)
{
// no domain was found : return a relative url, add vdir if any
uri = new Uri(global::umbraco.IO.SystemDirectories.Root + path, UriKind.Relative);
}
else
{
// a domain was found : return an absolute or relative url
// cannot handle vdir, has to be in domain uri
if (!absolute && current != null && domainUri.GetLeftPart(UriPartial.Authority) == current.GetLeftPart(UriPartial.Authority))
uri = new Uri(domainUri.AbsolutePath.TrimEnd('/') + path, UriKind.Relative); // relative
else
uri = new Uri(domainUri.GetLeftPart(UriPartial.Path).TrimEnd('/') + path); // absolute
}
return UriFromUmbraco(uri);
}
IEnumerable<Uri> AssembleUrls(IEnumerable<Uri> domainUris, string path, Uri current)
{
if (domainUris.Any())
{
return domainUris.Select(domainUri => new Uri(domainUri.GetLeftPart(UriPartial.Path).TrimEnd('/') + path));
}
else
{
// no domain was found : return a relative url, add vdir if any
return new Uri[] { new Uri(global::umbraco.IO.SystemDirectories.Root + path, UriKind.Relative) };
}
}
Uri DomainUriAtNode(int nodeId, Uri current)
{
// be safe
if (nodeId <= 0)
return null;
// apply filter on domains defined on that node
var domainAndUri = Domains.DomainMatch(Domain.GetDomainsById(nodeId), current, true);
return domainAndUri == null ? null : domainAndUri.Uri;
}
IEnumerable<Uri> DomainUrisAtNode(int nodeId, Uri current)
{
// be safe
if (nodeId <= 0)
return new Uri[] { };
var domainAndUris = Domains.DomainMatches(Domain.GetDomainsById(nodeId), current);
return domainAndUris.Select(d => d.Uri);
}
#endregion
#region Map public urls to/from umbraco urls
// fixme - what about vdir?
// path = path.Substring(UriUtility.AppVirtualPathPrefix.Length); // remove virtual directory
public static Uri UriFromUmbraco(Uri uri)
{
var path = uri.GetSafeAbsolutePath();
if (path == "/")
return uri;
if (!global::umbraco.GlobalSettings.UseDirectoryUrls)
path += ".aspx";
else if (global::umbraco.UmbracoSettings.AddTrailingSlash)
path += "/";
return uri.Rewrite(path);
}
public static Uri UriToUmbraco(Uri uri)
{
var path = uri.GetSafeAbsolutePath();
path = path.ToLower();
if (path != "/")
path = path.TrimEnd('/');
if (path.EndsWith(".aspx"))
path = path.Substring(0, path.Length - ".aspx".Length);
return uri.Rewrite(path);
}
#endregion
}
}

View File

@@ -1,31 +0,0 @@
using System;
namespace Umbraco.Web.Routing
{
/// <summary>
/// Specifies the relative weight of an <c>IRequestDocumentResolver</c> implementation.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
internal class RequestDocumentResolverWeightAttribute : Attribute
{
/// <summary>
/// Gets the default weight.
/// </summary>
public const int DefaultWeight = 100;
/// <summary>
/// Initializes a new instance of the <see cref="RequestDocumentResolverWeightAttribute"/> class with the weight.
/// </summary>
/// <param name="weight">The weight.</param>
public RequestDocumentResolverWeightAttribute(int weight)
: base()
{
this.Weight = weight;
}
/// <summary>
/// Gets the weight.
/// </summary>
public int Weight { get; private set; }
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Umbraco.Core;
using Umbraco.Core.Resolving;
namespace Umbraco.Web.Routing
{
class RequestDocumentResolversResolver : ResolverBase<RequestDocumentResolversResolver>
{
internal RequestDocumentResolversResolver(IEnumerable<IRequestDocumentResolver> resolvers, IRequestDocumentLastChanceResolver lastChanceResolver)
{
_resolvers.AddRange(resolvers);
_lastChanceResolver.Value = lastChanceResolver;
}
#region LastChanceResolver
SingleResolved<IRequestDocumentLastChanceResolver> _lastChanceResolver = new SingleResolved<IRequestDocumentLastChanceResolver>(true);
public IRequestDocumentLastChanceResolver RequestDocumentLastChanceResolver
{
get { return _lastChanceResolver.Value; }
set { _lastChanceResolver.Value = value; }
}
#endregion
#region Resolvers
ManyWeightedResolved<IRequestDocumentResolver> _resolvers = new ManyWeightedResolved<IRequestDocumentResolver>();
public IEnumerable<IRequestDocumentResolver> RequestDocumentResolvers
{
get { return _resolvers.Values; }
}
public ManyWeightedResolved<IRequestDocumentResolver> RequestDocumentResolversResolution
{
get { return _resolvers; }
}
#endregion
}
}

View File

@@ -1,5 +1,6 @@
using System.Diagnostics;
using System.Xml;
using Umbraco.Core.Resolving;
namespace Umbraco.Web.Routing
{
@@ -10,7 +11,7 @@ namespace Umbraco.Web.Routing
// at the moment aliases are not cleaned up into nice urls
//
[RequestDocumentResolverWeight(50)]
[ResolutionWeight(50)]
internal class ResolveByAlias : IRequestDocumentResolver
{
static readonly TraceSource Trace = new TraceSource("ResolveByAlias");

View File

@@ -1,13 +1,14 @@
using System;
using System.Diagnostics;
using System.Xml;
using Umbraco.Core.Resolving;
namespace Umbraco.Web.Routing
{
// handles /1234 where 1234 is the id of a document
//
[RequestDocumentResolverWeight(20)]
[ResolutionWeight(20)]
internal class ResolveById : IRequestDocumentResolver
{
static readonly TraceSource Trace = new TraceSource("ResolveById");

View File

@@ -1,12 +1,13 @@
using System.Diagnostics;
using System.Xml;
using Umbraco.Core.Resolving;
namespace Umbraco.Web.Routing
{
// handles "/foo/bar" where "/foo/bar" is the path to a document
//
[RequestDocumentResolverWeight(10)]
[ResolutionWeight(10)]
internal class ResolveByNiceUrl : IRequestDocumentResolver
{
static readonly TraceSource Trace = new TraceSource("ResolveByNiceUrl");

View File

@@ -1,5 +1,6 @@
using System.Diagnostics;
using System.Xml;
using Umbraco.Core.Resolving;
using umbraco.cms.businesslogic.template;
namespace Umbraco.Web.Routing
@@ -8,7 +9,7 @@ namespace Umbraco.Web.Routing
// handles /foo/bar/<template> where <template> is a valid template alias
// and /foo/bar the nice url of a document
//
[RequestDocumentResolverWeight(30)]
[ResolutionWeight(30)]
internal class ResolveByNiceUrlAndTemplate : ResolveByNiceUrl, IRequestDocumentResolver
{
static readonly TraceSource Trace = new TraceSource("ResolveByNiceUrlAndTemplate");

View File

@@ -1,5 +1,6 @@
using System.Diagnostics;
using System.Xml;
using Umbraco.Core.Resolving;
using umbraco;
namespace Umbraco.Web.Routing
@@ -11,7 +12,7 @@ namespace Umbraco.Web.Routing
//
// we're keeping it here only for backward compatibility.
//
[RequestDocumentResolverWeight(40)]
[ResolutionWeight(40)]
internal class ResolveByProfile : ResolveByNiceUrl, IRequestDocumentResolver
{
static readonly TraceSource Trace = new TraceSource("ResolveByProfile");

View File

@@ -1,112 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Umbraco.Core;
namespace Umbraco.Web.Routing
{
// fixme - this class is broken in various ways
// + we can't reproduce that sort of code for everything we need to discover
/// <summary>
/// Represents a collection of ILookup used for routing that are registered in the application
/// </summary>
internal class RouteLookups
{
private static readonly List<IRequestDocumentResolver> Lookups = new List<IRequestDocumentResolver>();
private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim();
/// <summary>
/// Singleton accessor
/// </summary>
public static RouteLookups Current { get; internal set; }
internal RouteLookups(IEnumerable<IRequestDocumentResolver> lookups)
{
Lookups.AddRange(SortByWeight(lookups));
}
/// <summary>
/// Returns all of the lookups
/// </summary>
/// <returns></returns>
public IEnumerable<IRequestDocumentResolver> GetLookups()
{
using(new ReadLock(Lock))
{
return Lookups;
}
}
/// <summary>
/// Removes an ILookup based on the specified Type
/// </summary>
/// <typeparam name="T"></typeparam>
public void RemoveLookup<T>()
where T : IRequestDocumentResolver
{
using (new WriteLock(Lock))
{
Lookups.Remove(Lookups.SingleOrDefault(x => x is T));
}
}
/// <summary>
/// Adds a new lookup to the end of the list
/// </summary>
/// <param name="lookup"></param>
public void AddLookup(IRequestDocumentResolver lookup)
{
using (var l = new UpgradeableReadLock(Lock))
{
if (CheckExists(lookup))
throw new InvalidOperationException(string.Format("The lookup type \"{0}\" already exists in the lookup collection.", lookup));
l.UpgradeToWriteLock();
Lookups.Add(lookup);
}
}
/// <summary>
/// Inserts a lookup at the specified index
/// </summary>
/// <param name="index"></param>
/// <param name="lookup"></param>
public void InsertLookup(int index, IRequestDocumentResolver lookup)
{
using (var l = new UpgradeableReadLock(Lock))
{
if (CheckExists(lookup))
throw new InvalidOperationException("The lookup type " + lookup + " already exists in the lookup collection");
l.UpgradeToWriteLock();
Lookups.Insert(index, lookup);
}
}
/// <summary>
/// checks if a lookup already exists by type
/// </summary>
/// <param name="lookup"></param>
/// <returns></returns>
private static bool CheckExists(IRequestDocumentResolver lookup)
{
return Lookups.Any(x => x.GetType() == lookup.GetType());
}
/// <summary>
/// Sorts the ILookups in the list based on an attribute weight if one is specified
/// </summary>
/// <param name="lookups"></param>
/// <returns></returns>
private static IEnumerable<IRequestDocumentResolver> SortByWeight(IEnumerable<IRequestDocumentResolver> lookups)
{
return lookups.OrderBy(x =>
{
var attribute = x.GetType().GetCustomAttributes(true).OfType<RequestDocumentResolverWeightAttribute>().SingleOrDefault();
return attribute == null ? RequestDocumentResolverWeightAttribute.DefaultWeight : attribute.Weight;
}).ToList();
}
}
}

View File

@@ -1,61 +0,0 @@
using System;
namespace Umbraco.Web.Routing
{
// this is a bi-directional cache that contains
// - nodeId to route (used for NiceUrl)
// - route to nodeId (used for inbound requests)
//
// a route is [rootId]/path/to/node
// where rootId is the id of the "site root" node
//
internal class RoutesCache
{
private static readonly RoutesCache Instance = new RoutesCache();
private static IRoutesCache _provider;
/// <summary>
/// public contructor assigns the DefaultRoutesCache as the default provider
/// </summary>
public RoutesCache()
:this(null)
{
}
/// <summary>
/// Constructor sets a custom provider if specified
/// </summary>
/// <param name="provider"></param>
internal RoutesCache(IRoutesCache provider)
{
_provider = provider ?? new DefaultRoutesCache();
}
/// <summary>
/// Set the routes cache provider
/// </summary>
/// <param name="provider"></param>
public static void SetProvider(IRoutesCache provider)
{
if (provider == null) throw new ArgumentNullException("provider");
_provider = provider;
}
/// <summary>
/// Singleton accessor
/// </summary>
public static RoutesCache Current
{
get { return Instance; }
}
/// <summary>
/// Get the current provider
/// </summary>
/// <returns></returns>
public IRoutesCache GetProvider()
{
return _provider;
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using Umbraco.Core.Resolving;
namespace Umbraco.Web.Routing
{
/// <summary>
/// Resolves the <see cref="IRoutesCache"/> implementation.
/// </summary>
class RoutesCacheResolver : SingleResolverBase<RoutesCacheResolver, IRoutesCache>
{
/// <summary>
/// Initializes a new instance of the <see cref="RoutesCacheResolve"/> class with an <see cref="IRoutesCache"/> implementation.
/// </summary>
/// <param name="routesCache">The <see cref="IRoutesCache"/> implementation.</param>
internal RoutesCacheResolver(IRoutesCache routesCache)
: base(routesCache)
{ }
/// <summary>
/// Gets or sets the <see cref="IRoutesCache"/> implementation.
/// </summary>
public IRoutesCache RoutesCache
{
get { return this.Value; }
set { this.Value = value; }
}
}
}

View File

@@ -5,29 +5,47 @@ namespace Umbraco.Web.Routing
{
/// <summary>
/// represents a request for one specified Umbraco document to be rendered by one specified template,
/// using one particular culture.
/// Provides context for the routing of a request.
/// </summary>
internal class RoutingContext
{
/// <summary>
/// Initializes a new instance of the <see cref="RoutingContext"/> class.
/// </summary>
/// <param name="umbracoContext">The Umbraco context.</param>
/// <param name="documentLookupsResolver">The document lookups resolver.</param>
/// <param name="contentStore">The content store.</param>
/// <param name="niceUrlResolver">The nice urls resolver.</param>
public RoutingContext(
UmbracoContext umbracoContext,
RouteLookups lookups,
IRequestDocumentLastChanceResolver lookupNotFound,
DocumentLookupsResolver documentLookupsResolver,
ContentStore contentStore,
NiceUrlResolver niceUrlResolver)
NiceUrlProvider niceUrlResolver)
{
UmbracoContext = umbracoContext;
RouteLookups = lookups;
LookupNotFound = lookupNotFound;
ContentStore = contentStore;
NiceUrlResolver = niceUrlResolver;
this.UmbracoContext = umbracoContext;
this.DocumentLookupsResolver = documentLookupsResolver;
this.ContentStore = contentStore;
this.NiceUrlProvider = niceUrlResolver;
}
/// <summary>
/// Gets the Umbraco context.
/// </summary>
public UmbracoContext UmbracoContext { get; private set; }
public RouteLookups RouteLookups { get; private set; }
public IRequestDocumentLastChanceResolver LookupNotFound { get; private set; }
/// <summary>
/// Gets the document lookups resolver.
/// </summary>
public DocumentLookupsResolver DocumentLookupsResolver { get; private set; }
/// <summary>
/// Gets the content store.
/// </summary>
public ContentStore ContentStore { get; private set; }
public NiceUrlResolver NiceUrlResolver { get; private set; }
/// <summary>
/// Gets the nice urls provider.
/// </summary>
public NiceUrlProvider NiceUrlProvider { get; private set; }
}
}

View File

@@ -240,23 +240,22 @@
<Compile Include="ContentStore.cs" />
<Compile Include="LegacyRequestInitializer.cs" />
<Compile Include="Mvc\ControllerExtensions.cs" />
<Compile Include="NiceUrlResolver.cs" />
<Compile Include="Routing\NiceUrlProvider.cs" />
<Compile Include="PluginResolverExtensions.cs" />
<Compile Include="Routing\Domains.cs" />
<Compile Include="Routing\RouteLookups.cs" />
<Compile Include="Routing\DocumentLookupsResolver.cs" />
<Compile Include="Routing\DocumentRequest.cs" />
<Compile Include="Routing\IRequestDocumentResolver.cs" />
<Compile Include="Routing\IRequestDocumentLastChanceResolver.cs" />
<Compile Include="Routing\IDocumentLookup.cs" />
<Compile Include="Routing\IDocumentLastChanceLookup.cs" />
<Compile Include="Routing\IRoutesCache.cs" />
<Compile Include="Routing\ResolveByAlias.cs" />
<Compile Include="Routing\ResolveById.cs" />
<Compile Include="Routing\ResolveByNiceUrl.cs" />
<Compile Include="Routing\ResolveByNiceUrlAndTemplate.cs" />
<Compile Include="Routing\ResolveByProfile.cs" />
<Compile Include="Routing\ResolveLastChance.cs" />
<Compile Include="Routing\RequestDocumentResolverWeightAttribute.cs" />
<Compile Include="Routing\LookupByAlias.cs" />
<Compile Include="Routing\LookupById.cs" />
<Compile Include="Routing\LookupByNiceUrl.cs" />
<Compile Include="Routing\LookupByNiceUrlAndTemplate.cs" />
<Compile Include="Routing\LookupByProfile.cs" />
<Compile Include="Routing\DefaultLastChanceLookup.cs" />
<Compile Include="Routing\DefaultRoutesCache.cs" />
<Compile Include="Routing\RoutesCache.cs" />
<Compile Include="Routing\RoutesCacheResolver.cs" />
<Compile Include="Routing\RoutingContext.cs" />
<Compile Include="umbraco.presentation\EnsureSystemPathsApplicationStartupHandler.cs" />
<Compile Include="umbraco.presentation\install\steps\database.ascx.cs">
@@ -1814,7 +1813,9 @@
<Content Include="umbraco.presentation\umbraco\dialogs\Preview.aspx" />
<Content Include="umbraco.presentation\umbraco\controls\passwordChanger.ascx" />
<Content Include="umbraco.presentation\umbraco\controls\ProgressBar.ascx" />
<Content Include="umbraco.presentation\umbraco\controls\ContentTypeControlNew.ascx" />
<Content Include="umbraco.presentation\umbraco\controls\ContentTypeControlNew.ascx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\controls\GenericProperties\GenericProperty.ascx" />
<Content Include="umbraco.presentation\umbraco\create\DLRScripting.ascx" />
<Content Include="umbraco.presentation\umbraco\controls\Images\ImageViewer.ascx" />

View File

@@ -35,8 +35,11 @@ namespace Umbraco.Web
IsReady = true // fixme
};
//create the route lookups singleton
RouteLookups.Current = new RouteLookups(ApplicationContext.Current.Plugins.ResolveLookups());
// create the resolvers
DocumentLookupsResolver.Current = new DocumentLookupsResolver(ApplicationContext.Current.Plugins.ResolveLookups(), new DefaultLastChanceLookup());
RoutesCacheResolver.Current = new RoutesCacheResolver(new DefaultRoutesCache());
Umbraco.Core.Resolving.Resolution.Freeze();
Trace.TraceInformation("AppDomain is initialized");
}

View File

@@ -132,7 +132,7 @@ namespace Umbraco.Web
set
{
_requestUrl = value;
this.UmbracoUrl = NiceUrlResolver.UriToUmbraco(_requestUrl);
this.UmbracoUrl = NiceUrlProvider.UriToUmbraco(_requestUrl);
}
}

View File

@@ -45,7 +45,7 @@ namespace Umbraco.Web
var umbracoContext = new UmbracoContext(
new HttpContextWrapper(httpContext),
ApplicationContext.Current,
RoutesCache.Current.GetProvider());
RoutesCacheResolver.Current.RoutesCache);
UmbracoContext.Current = umbracoContext;
// NO!
@@ -54,12 +54,11 @@ namespace Umbraco.Web
//create a content store
var contentStore = new ContentStore(umbracoContext);
//create the nice urls
var niceUrls = new NiceUrlResolver(contentStore, umbracoContext);
var niceUrls = new NiceUrlProvider(contentStore, umbracoContext);
//create the RoutingContext (one per http request)
var routingContext = new RoutingContext(
umbracoContext,
RouteLookups.Current,
new ResolveLastChance(),
DocumentLookupsResolver.Current,
contentStore,
niceUrls);
// NOT HERE BUT SEE **THERE** BELOW
@@ -107,11 +106,11 @@ namespace Umbraco.Web
//**THERE** we should create the doc request
// before, we're not sure we handling a doc request
docreq.ResolveDomain();
docreq.LookupDomain();
if (docreq.IsRedirect)
httpContext.Response.Redirect(docreq.RedirectUrl, true);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = docreq.Culture;
docreq.ResolveDocument();
docreq.LookupDocument();
if (docreq.IsRedirect)
httpContext.Response.Redirect(docreq.RedirectUrl, true);

View File

@@ -355,10 +355,8 @@ namespace umbraco
/// <returns>String with a friendly url from a node</returns>
public static string NiceUrl(int nodeID)
{
return Umbraco.Web.UmbracoContext.Current
.DocumentRequest
.RoutingContext
.NiceUrlResolver.GetNiceUrl(nodeID);
var niceUrlsProvider = Umbraco.Web.UmbracoContext.Current.DocumentRequest.RoutingContext.NiceUrlProvider;
return niceUrlsProvider.GetNiceUrl(nodeID);
}
/// <summary>
@@ -380,10 +378,8 @@ namespace umbraco
/// <returns>String with a friendly url with full domain from a node</returns>
public static string NiceUrlWithDomain(int nodeID)
{
return Umbraco.Web.UmbracoContext.Current
.DocumentRequest
.RoutingContext
.NiceUrlResolver.GetNiceUrl(nodeID, Umbraco.Web.UmbracoContext.Current.UmbracoUrl, true);
var niceUrlsProvider = Umbraco.Web.UmbracoContext.Current.DocumentRequest.RoutingContext.NiceUrlProvider;
return niceUrlsProvider.GetNiceUrl(nodeID, Umbraco.Web.UmbracoContext.Current.UmbracoUrl, true);
}