From 8f278bcaa52b31bee4bfbfe33c4b06e94278ecfd Mon Sep 17 00:00:00 2001 From: "shannon@ShandemVaio" Date: Fri, 20 Jul 2012 23:42:55 +0600 Subject: [PATCH] Added singleton for managing ILookups collection, allows for adding/removing/inserting at runtime/startup --- src/Umbraco.Core/ApplicationContext.cs | 2 +- src/Umbraco.Web/PluginResolverExtensions.cs | 2 +- src/Umbraco.Web/Routing/DocumentRequest.cs | 3 +- src/Umbraco.Web/Routing/RouteLookups.cs | 105 ++++++++++++++++++ src/Umbraco.Web/Routing/RoutingEnvironment.cs | 15 +-- src/Umbraco.Web/Umbraco.Web.csproj | 1 + src/Umbraco.Web/UmbracoApplication.cs | 4 + src/Umbraco.Web/UmbracoModule.cs | 2 +- 8 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 src/Umbraco.Web/Routing/RouteLookups.cs diff --git a/src/Umbraco.Core/ApplicationContext.cs b/src/Umbraco.Core/ApplicationContext.cs index 1f39c1b9ee..6d4892e911 100644 --- a/src/Umbraco.Core/ApplicationContext.cs +++ b/src/Umbraco.Core/ApplicationContext.cs @@ -24,7 +24,7 @@ namespace Umbraco.Core /// /// Singleton accessor /// - public static ApplicationContext Current { get; set; } + public static ApplicationContext Current { get; internal set; } // IsReady is set to true by the boot manager once it has successfully booted // note - the original umbraco module checks on content.Instance in umbraco.dll diff --git a/src/Umbraco.Web/PluginResolverExtensions.cs b/src/Umbraco.Web/PluginResolverExtensions.cs index fbbf81c853..102172f15f 100644 --- a/src/Umbraco.Web/PluginResolverExtensions.cs +++ b/src/Umbraco.Web/PluginResolverExtensions.cs @@ -7,7 +7,7 @@ using umbraco.BusinessLogic.Utils; namespace Umbraco.Web { - /// + /// /// Extension methods for the PluginResolver /// public static class PluginResolverExtensions diff --git a/src/Umbraco.Web/Routing/DocumentRequest.cs b/src/Umbraco.Web/Routing/DocumentRequest.cs index 65844d84c8..bb51181849 100644 --- a/src/Umbraco.Web/Routing/DocumentRequest.cs +++ b/src/Umbraco.Web/Routing/DocumentRequest.cs @@ -251,7 +251,8 @@ namespace Umbraco.Web.Routing // the first successful lookup, if any, will set this.Node, and may also set this.Template // some lookups may implement caching Trace.TraceInformation("{0}Begin lookup", tracePrefix); - _environment.Lookups.Any(lookup => lookup.LookupDocument(this)); + var lookups = _environment.RouteLookups.GetLookups(); + lookups.Any(lookup => lookup.LookupDocument(this)); Trace.TraceInformation("{0}End lookup, {1}", tracePrefix, (this.HasNode ? "a document was found" : "no document was found")); // fixme - not handling umbracoRedirect diff --git a/src/Umbraco.Web/Routing/RouteLookups.cs b/src/Umbraco.Web/Routing/RouteLookups.cs new file mode 100644 index 0000000000..9e6671c9e0 --- /dev/null +++ b/src/Umbraco.Web/Routing/RouteLookups.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using Umbraco.Core; + +namespace Umbraco.Web.Routing +{ + /// + /// Represents a collection of ILookups used for routing that are registered in the application + /// + internal class RouteLookups + { + private static readonly List Lookups = new List(); + private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim(); + + /// + /// Singleton accessor + /// + public static RouteLookups Current { get; internal set; } + + internal RouteLookups(IEnumerable lookups) + { + Lookups.AddRange(SortByWeight(lookups)); + } + + /// + /// Returns all of the lookups + /// + /// + public IEnumerable GetLookups() + { + return Lookups; + } + + /// + /// Removes an ILookup based on the specified Type + /// + /// + public void RemoveLookup() + where T : ILookup + { + using (new WriteLock(Lock)) + { + Lookups.Remove(Lookups.SingleOrDefault(x => x is T)); + } + } + + /// + /// Adds a new lookup to the end of the list + /// + /// + public void AddLookup(ILookup lookup) + { + if (CheckExists(lookup)) + throw new InvalidOperationException("The lookup type " + lookup.GetType() + " already exists in the lookup collection"); + + using (new WriteLock(Lock)) + { + Lookups.Add(lookup); + } + } + + /// + /// Inserts a lookup at the specified index + /// + /// + /// + public void InsertLookup(int index, ILookup lookup) + { + if (CheckExists(lookup)) + throw new InvalidOperationException("The lookup type " + lookup.GetType() + " already exists in the lookup collection"); + + using (new WriteLock(Lock)) + { + Lookups.Insert(index, lookup); + } + } + + /// + /// checks if a lookup already exists by type + /// + /// + /// + private static bool CheckExists(ILookup lookup) + { + return Lookups.Any(x => x.GetType() == lookup.GetType()); + } + + /// + /// Sorts the ILookups in the list based on an attribute weight if one is specified + /// + /// + /// + private static IEnumerable SortByWeight(IEnumerable lookups) + { + return lookups.OrderBy(x => + { + var attribute = x.GetType().GetCustomAttributes(true).OfType().SingleOrDefault(); + return attribute == null ? LookupWeightAttribute.DefaultWeight : attribute.Weight; + }).ToList(); + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Routing/RoutingEnvironment.cs b/src/Umbraco.Web/Routing/RoutingEnvironment.cs index 0affeb6799..0c5d770e86 100644 --- a/src/Umbraco.Web/Routing/RoutingEnvironment.cs +++ b/src/Umbraco.Web/Routing/RoutingEnvironment.cs @@ -11,25 +11,16 @@ namespace Umbraco.Web.Routing internal class RoutingEnvironment { public RoutingEnvironment( - IEnumerable lookups, + RouteLookups lookups, ILookupNotFound lookupNotFound, ContentStore contentStore) { - Lookups = SortByPartWeight(lookups); + RouteLookups = lookups; LookupNotFound = lookupNotFound; ContentStore = contentStore; } - private static IEnumerable SortByPartWeight(IEnumerable lookups) - { - return lookups.OrderBy(x => - { - var attribute = x.GetType().GetCustomAttributes(true).OfType().SingleOrDefault(); - return attribute == null ? LookupWeightAttribute.DefaultWeight : attribute.Weight; - }).ToList(); - } - - public IEnumerable Lookups { get; private set; } + public RouteLookups RouteLookups { get; private set; } public ILookupNotFound LookupNotFound { get; private set; } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index b3ec0b677e..3b5d82ee48 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -242,6 +242,7 @@ + diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs index 635d873bf5..5febadc78a 100644 --- a/src/Umbraco.Web/UmbracoApplication.cs +++ b/src/Umbraco.Web/UmbracoApplication.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Linq; using System.Text; using Umbraco.Core; +using Umbraco.Web.Routing; namespace Umbraco.Web { @@ -34,6 +35,9 @@ namespace Umbraco.Web IsReady = true // fixme }; + //create the route lookups singleton + RouteLookups.Current = new RouteLookups(ApplicationContext.Current.Plugins.ResolveLookups()); + Trace.TraceInformation("AppDomain is initialized"); } diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 1087e61fe3..bcd976c8d3 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -42,7 +42,7 @@ namespace Umbraco.Web var niceUrls = new NiceUrlResolver(contentStore, umbracoContext, RoutesCache.Current.GetProvider()); //create the RoutingEnvironment (one per http request as it relies on the umbraco context!) var routingEnvironment = new RoutingEnvironment( - ApplicationContext.Current.Plugins.ResolveLookups().ToArray(), + RouteLookups.Current, new LookupFor404(contentStore), contentStore); // create the new document request which will cleanup the uri once and for all