diff --git a/src/Umbraco.Web/Routing/DefaultLastChanceLookup.cs b/src/Umbraco.Web/Routing/DefaultLastChanceLookup.cs
deleted file mode 100644
index 674a6e64a4..0000000000
--- a/src/Umbraco.Web/Routing/DefaultLastChanceLookup.cs
+++ /dev/null
@@ -1,228 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Reflection;
-using System.Web;
-using System.Xml;
-using Umbraco.Core.Logging;
-using Umbraco.Core.Models;
-using umbraco.IO;
-using umbraco.interfaces;
-
-namespace Umbraco.Web.Routing
-{
- ///
- /// Provides an implementation of that handles backward compatilibty with legacy INotFoundHandler.
- ///
- internal class DefaultLastChanceLookup : IDocumentLastChanceLookup
- {
- // notes
- //
- // at the moment we load the legacy INotFoundHandler
- // excluding those that have been replaced by proper lookups,
- // and run them.
- //
- // when we finaly obsolete INotFoundHandler, we'll have to move
- // over here code from legacy requestHandler.hande404, which
- // basically uses umbraco.library.GetCurrentNotFoundPageId();
- // which also would need to be refactored / migrated here.
- //
- // the best way to do this would be to create a DefaultLastChanceLookup2
- // that would do everything by itself, and let ppl use it if they
- // want, then make it the default one, then remove this one.
-
- ///
- /// Tries to find and assign an Umbraco document to a PublishedContentRequest.
- ///
- /// The PublishedContentRequest.
- /// A value indicating whether an Umbraco document was found and assigned.
- public bool TrySetDocument(PublishedContentRequest docRequest)
- {
- docRequest.PublishedContent = HandlePageNotFound(docRequest);
- return docRequest.HasNode;
- }
-
- #region Copied over from presentation.requestHandler
-
- //FIXME: this is temporary and should be obsoleted
-
- string GetLegacyUrlForNotFoundHandlers(PublishedContentRequest docRequest)
- {
- // that's not backward-compatible because when requesting "/foo.aspx"
- // 4.9 : url = "foo.aspx"
- // 4.10 : url = "/foo"
- //return docRequest.Uri.AbsolutePath;
-
- // so we have to run the legacy code for url preparation :-(
-
- // code from requestModule.UmbracoRewrite
- string tmp = HttpContext.Current.Request.Path.ToLower();
-
- // note: requestModule.UmbracoRewrite also does some confusing stuff
- // with stripping &umbPage from the querystring?! ignored.
-
- // code from requestHandler.cleanUrl
- string root = Umbraco.Core.IO.SystemDirectories.Root.ToLower();
- if (!string.IsNullOrEmpty(root) && tmp.StartsWith(root))
- tmp = tmp.Substring(root.Length);
- tmp = tmp.TrimEnd('/');
- if (tmp == "/default.aspx")
- tmp = string.Empty;
- else if (tmp == root)
- tmp = string.Empty;
-
- // code from UmbracoDefault.Page_PreInit
- if (tmp != "" && HttpContext.Current.Request["umbPageID"] == null)
- {
- string tryIntParse = tmp.Replace("/", "").Replace(".aspx", string.Empty);
- int result;
- if (int.TryParse(tryIntParse, out result))
- tmp = tmp.Replace(".aspx", string.Empty);
- }
- else if (!string.IsNullOrEmpty(HttpContext.Current.Request["umbPageID"]))
- {
- int result;
- if (int.TryParse(HttpContext.Current.Request["umbPageID"], out result))
- {
- tmp = HttpContext.Current.Request["umbPageID"];
- }
- }
-
- // code from requestHandler.ctor
- if (tmp != "")
- tmp = tmp.Substring(1);
-
- return tmp;
- }
-
- IPublishedContent HandlePageNotFound(PublishedContentRequest docRequest)
- {
- LogHelper.Debug("Running for url='{0}'.", () => docRequest.Uri.AbsolutePath);
-
- //XmlNode currentPage = null;
- IPublishedContent currentPage = null;
- var url = GetLegacyUrlForNotFoundHandlers(docRequest);
-
- foreach (var handler in GetNotFoundHandlers())
- {
- if (handler.Execute(url) && handler.redirectID > 0)
- {
- //currentPage = umbracoContent.GetElementById(handler.redirectID.ToString());
- currentPage = docRequest.RoutingContext.PublishedContentStore.GetDocumentById(
- docRequest.RoutingContext.UmbracoContext,
- handler.redirectID);
-
- // FIXME - could it be null?
-
- LogHelper.Debug("Handler '{0}' found node with id={1}.", () => handler.GetType().FullName, () => handler.redirectID);
-
- //// check for caching
- //if (handler.CacheUrl)
- //{
- // if (url.StartsWith("/"))
- // url = "/" + url;
-
- // var cacheKey = (currentDomain == null ? "" : currentDomain.Name) + url;
- // var culture = currentDomain == null ? null : currentDomain.Language.CultureAlias;
- // SetCache(cacheKey, new CacheEntry(handler.redirectID.ToString(), culture));
-
- // HttpContext.Current.Trace.Write("NotFoundHandler",
- // string.Format("Added to cache '{0}', {1}.", url, handler.redirectID));
- //}
-
- break;
- }
- }
-
- return currentPage;
- }
-
- static IEnumerable _customHandlerTypes = null;
- static readonly object CustomHandlerTypesLock = new object();
-
- IEnumerable InitializeNotFoundHandlers()
- {
- // initialize handlers
- // create the definition cache
-
- LogHelper.Debug("Registering custom handlers.");
-
- var customHandlerTypes = new List();
-
- var customHandlers = new XmlDocument();
- customHandlers.Load(Umbraco.Core.IO.IOHelper.MapPath(Umbraco.Core.IO.SystemFiles.NotFoundhandlersConfig));
-
- foreach (XmlNode n in customHandlers.DocumentElement.SelectNodes("notFound"))
- {
- var assemblyName = n.Attributes.GetNamedItem("assembly").Value;
-
- var typeName = n.Attributes.GetNamedItem("type").Value;
- string ns = assemblyName;
- var nsAttr = n.Attributes.GetNamedItem("namespace");
- if (nsAttr != null && !string.IsNullOrWhiteSpace(nsAttr.Value))
- ns = nsAttr.Value;
-
- if (assemblyName == "umbraco" && (ns + "." + typeName) != "umbraco.handle404")
- {
- // skip those that are in umbraco.dll because we have replaced them with IDocumentLookups
- // but do not skip "handle404" as that's the built-in legacy final handler, and for the time
- // being people will have it in their config.
- continue;
- }
-
- LogHelper.Debug("Registering '{0}.{1},{2}'.", () => ns, () => typeName, () => assemblyName);
-
- Type type = null;
- try
- {
- //TODO: This isn't a good way to load the assembly, its already in the Domain so we should be getting the type
- // this loads the assembly into the wrong assembly load context!!
-
- var assembly = Assembly.LoadFrom(Umbraco.Core.IO.IOHelper.MapPath(Umbraco.Core.IO.SystemDirectories.Bin + "/" + assemblyName + ".dll"));
- type = assembly.GetType(ns + "." + typeName);
- }
- catch (Exception e)
- {
- LogHelper.Error("Error registering handler, ignoring.", e);
- }
-
- if (type != null)
- customHandlerTypes.Add(type);
- }
-
- return customHandlerTypes;
- }
-
- IEnumerable GetNotFoundHandlers()
- {
- // instanciate new handlers
- // using definition cache
-
- lock (CustomHandlerTypesLock)
- {
- if (_customHandlerTypes == null)
- _customHandlerTypes = InitializeNotFoundHandlers();
- }
-
- var handlers = new List();
-
- foreach (var type in _customHandlerTypes)
- {
- try
- {
- var handler = Activator.CreateInstance(type) as INotFoundHandler;
- if (handler != null)
- handlers.Add(handler);
- }
- catch (Exception e)
- {
- LogHelper.Error(string.Format("Error instanciating handler {0}, ignoring.", type.FullName), e);
- }
- }
-
- return handlers;
- }
-
- #endregion
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Routing/LastChanceLookupResolver.cs b/src/Umbraco.Web/Routing/LastChanceLookupResolver.cs
index 0feadc8a4b..fc77661f95 100644
--- a/src/Umbraco.Web/Routing/LastChanceLookupResolver.cs
+++ b/src/Umbraco.Web/Routing/LastChanceLookupResolver.cs
@@ -8,9 +8,13 @@ namespace Umbraco.Web.Routing
///
internal sealed class LastChanceLookupResolver : SingleObjectResolverBase
{
-
- internal LastChanceLookupResolver(IDocumentLastChanceLookup lastChanceLookup)
- : base(lastChanceLookup)
+ internal LastChanceLookupResolver()
+ : base(true)
+ {
+ }
+
+ internal LastChanceLookupResolver(IDocumentLastChanceLookup lastChanceLookup)
+ : base(lastChanceLookup, true)
{
}
diff --git a/src/Umbraco.Web/Routing/LookupByAlias.cs b/src/Umbraco.Web/Routing/LookupByAlias.cs
index 0c0c023d23..530f12fcd6 100644
--- a/src/Umbraco.Web/Routing/LookupByAlias.cs
+++ b/src/Umbraco.Web/Routing/LookupByAlias.cs
@@ -24,7 +24,6 @@ namespace Umbraco.Web.Routing
/// A value indicating whether an Umbraco document was found and assigned.
public bool TrySetDocument(PublishedContentRequest docRequest)
{
-
IPublishedContent node = null;
if (docRequest.Uri.AbsolutePath != "/") // no alias if "/"
diff --git a/src/Umbraco.Web/Routing/LookupByLegacy404.cs b/src/Umbraco.Web/Routing/LookupByLegacy404.cs
new file mode 100644
index 0000000000..be73fa81c4
--- /dev/null
+++ b/src/Umbraco.Web/Routing/LookupByLegacy404.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Umbraco.Core;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Models;
+
+namespace Umbraco.Web.Routing
+{
+ internal class LookupByLegacy404 : IPublishedContentLookup
+ {
+ ///
+ /// Tries to find and assign an Umbraco document to a PublishedContentRequest.
+ ///
+ /// The PublishedContentRequest.
+ /// A value indicating whether an Umbraco document was found and assigned.
+ public bool TrySetDocument(PublishedContentRequest pcr)
+ {
+ LogHelper.Debug("Looking for a page to handle 404.");
+
+ // TODO - replace the whole logic and stop calling into library!
+ var error404 = global::umbraco.library.GetCurrentNotFoundPageId();
+ var id = int.Parse(error404);
+
+ IPublishedContent content = null;
+
+ if (id > 0)
+ {
+ LogHelper.Debug("Got id={0}.", () => id);
+
+ content = pcr.RoutingContext.PublishedContentStore.GetDocumentById(
+ pcr.RoutingContext.UmbracoContext,
+ id);
+
+ if (content == null)
+ LogHelper.Debug("Could not find content with that id.");
+ else
+ LogHelper.Debug("Found corresponding content.");
+ }
+ else
+ {
+ LogHelper.Debug("Got nothing.");
+ }
+
+ pcr.PublishedContent = content;
+ pcr.Is404 = true;
+ return content != null;
+ }
+ }
+}
diff --git a/src/Umbraco.Web/Routing/LookupByNotFoundHandlers.cs b/src/Umbraco.Web/Routing/LookupByNotFoundHandlers.cs
new file mode 100644
index 0000000000..09ba92d506
--- /dev/null
+++ b/src/Umbraco.Web/Routing/LookupByNotFoundHandlers.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Reflection;
+using System.Web;
+using System.Xml;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Models;
+using umbraco.IO;
+using umbraco.interfaces;
+
+namespace Umbraco.Web.Routing
+{
+ ///
+ /// Provides an implementation of that handles backward compatilibty with legacy INotFoundHandler.
+ ///
+ internal class LookupByNotFoundHandlers : IPublishedContentLookup
+ {
+ // notes
+ //
+ // at the moment we load the legacy INotFoundHandler
+ // excluding those that have been replaced by proper finders,
+ // and run them.
+
+ ///
+ /// Tries to find and assign an Umbraco document to a PublishedContentRequest.
+ ///
+ /// The PublishedContentRequest.
+ /// A value indicating whether an Umbraco document was found and assigned.
+ public bool TrySetDocument(PublishedContentRequest docRequest)
+ {
+ HandlePageNotFound(docRequest);
+ return docRequest.HasNode;
+ }
+
+ #region Copied over and adapted from presentation.requestHandler
+
+ //FIXME: this is temporary and should be obsoleted
+
+ void HandlePageNotFound(PublishedContentRequest docRequest)
+ {
+ LogHelper.Debug("Running for url='{0}'.", () => docRequest.Uri.AbsolutePath);
+
+ var url = NotFoundHandlerHelper.GetLegacyUrlForNotFoundHandlers();
+
+ foreach (var handler in GetNotFoundHandlers())
+ {
+ IPublishedContentLookup lookup = null;
+
+ LogHelper.Debug("Handler '{0}'.", () => handler.GetType().FullName);
+
+ // replace with our own implementation
+ if (handler is global::umbraco.SearchForAlias)
+ lookup = new LookupByAlias();
+ else if (handler is global::umbraco.SearchForProfile)
+ lookup = new LookupByProfile();
+ else if (handler is global::umbraco.SearchForTemplate)
+ lookup = new LookupByNiceUrlAndTemplate();
+ else if (handler is global::umbraco.handle404)
+ lookup = new LookupByLegacy404();
+
+ if (lookup != null)
+ {
+ LogHelper.Debug("Replace handler '{0}' by new lookup '{1}'.", () => handler.GetType().FullName, () => lookup.GetType().FullName);
+ if (lookup.TrySetDocument(docRequest))
+ {
+ // do NOT set docRequest.PublishedContent again here as
+ // it would clear any template that the finder might have set
+ LogHelper.Debug("Lookup '{0}' found node with id={1}.", () => lookup.GetType().FullName, () => docRequest.PublishedContent.Id);
+ if (docRequest.Is404)
+ LogHelper.Debug("Lookup '{0}' set status to 404.", () => lookup.GetType().FullName);
+ return;
+ }
+ }
+
+ // else it's a legacy handler, run
+
+ if (handler.Execute(url) && handler.redirectID > 0)
+ {
+ docRequest.PublishedContent = docRequest.RoutingContext.PublishedContentStore.GetDocumentById(
+ docRequest.RoutingContext.UmbracoContext,
+ handler.redirectID);
+
+ if (!docRequest.HasNode)
+ {
+ LogHelper.Debug("Handler '{0}' found node with id={1} which is not valid.", () => handler.GetType().FullName, () => handler.redirectID);
+ break;
+ }
+
+ LogHelper.Debug("Handler '{0}' found valid node with id={1}.", () => handler.GetType().FullName, () => handler.redirectID);
+
+ if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404)
+ {
+ LogHelper.Debug("Handler '{0}' set status code to 404.", () => handler.GetType().FullName);
+ docRequest.Is404 = true;
+ }
+
+ //// check for caching
+ //if (handler.CacheUrl)
+ //{
+ // if (url.StartsWith("/"))
+ // url = "/" + url;
+
+ // var cacheKey = (currentDomain == null ? "" : currentDomain.Name) + url;
+ // var culture = currentDomain == null ? null : currentDomain.Language.CultureAlias;
+ // SetCache(cacheKey, new CacheEntry(handler.redirectID.ToString(), culture));
+
+ // HttpContext.Current.Trace.Write("NotFoundHandler",
+ // string.Format("Added to cache '{0}', {1}.", url, handler.redirectID));
+ //}
+
+ break;
+ }
+ }
+ }
+
+ IEnumerable GetNotFoundHandlers()
+ {
+ // instanciate new handlers
+ // using definition cache
+
+ var handlers = new List();
+
+ foreach (var type in NotFoundHandlerHelper.CustomHandlerTypes)
+ {
+ try
+ {
+ var handler = Activator.CreateInstance(type) as INotFoundHandler;
+ if (handler != null)
+ handlers.Add(handler);
+ }
+ catch (Exception e)
+ {
+ LogHelper.Error(string.Format("Error instanciating handler {0}, ignoring.", type.FullName), e);
+ }
+ }
+
+ return handlers;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs b/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs
new file mode 100644
index 0000000000..595c8fd7c9
--- /dev/null
+++ b/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Web;
+using System.Xml;
+using System.Reflection;
+
+using Umbraco.Core;
+using Umbraco.Core.Logging;
+
+namespace Umbraco.Web.Routing
+{
+ // provides internal access to legacy url -- should get rid of it eventually
+ internal static class NotFoundHandlerHelper
+ {
+ const string ContextKey = "Umbraco.Web.Routing.NotFoundHandlerHelper.Url";
+
+ static NotFoundHandlerHelper()
+ {
+ InitializeNotFoundHandlers();
+ }
+
+ public static string GetLegacyUrlForNotFoundHandlers()
+ {
+ // that's not backward-compatible because when requesting "/foo.aspx"
+ // 4.9 : url = "foo.aspx"
+ // 4.10 : url = "/foo"
+ //return pcr.Uri.AbsolutePath;
+
+ // so we have to run the legacy code for url preparation :-(
+
+ var httpContext = HttpContext.Current;
+
+ if (httpContext == null)
+ return "";
+
+ var url = httpContext.Items[ContextKey] as string;
+ if (url != null)
+ return url;
+
+ // code from requestModule.UmbracoRewrite
+ string tmp = httpContext.Request.Path.ToLower();
+
+ // note: requestModule.UmbracoRewrite also did some stripping of &umbPage
+ // from the querystring... that was in v3.x to fix some issues with pre-forms
+ // auth. Paul Sterling confirmed in jan. 2013 that we can get rid of it.
+
+ // code from requestHandler.cleanUrl
+ string root = Umbraco.Core.IO.SystemDirectories.Root.ToLower();
+ if (!string.IsNullOrEmpty(root) && tmp.StartsWith(root))
+ tmp = tmp.Substring(root.Length);
+ tmp = tmp.TrimEnd('/');
+ if (tmp == "/default.aspx")
+ tmp = string.Empty;
+ else if (tmp == root)
+ tmp = string.Empty;
+
+ // code from UmbracoDefault.Page_PreInit
+ if (tmp != "" && httpContext.Request["umbPageID"] == null)
+ {
+ string tryIntParse = tmp.Replace("/", "").Replace(".aspx", string.Empty);
+ int result;
+ if (int.TryParse(tryIntParse, out result))
+ tmp = tmp.Replace(".aspx", string.Empty);
+ }
+ else if (!string.IsNullOrEmpty(httpContext.Request["umbPageID"]))
+ {
+ int result;
+ if (int.TryParse(httpContext.Request["umbPageID"], out result))
+ {
+ tmp = httpContext.Request["umbPageID"];
+ }
+ }
+
+ // code from requestHandler.ctor
+ if (tmp != "")
+ tmp = tmp.Substring(1);
+
+ httpContext.Items[ContextKey] = tmp;
+ return tmp;
+ }
+
+ static IEnumerable _customHandlerTypes = null;
+
+ static void InitializeNotFoundHandlers()
+ {
+ // initialize handlers
+ // create the definition cache
+
+ LogHelper.Debug("Registering custom handlers.");
+
+ var customHandlerTypes = new List();
+
+ var customHandlers = new XmlDocument();
+ customHandlers.Load(Umbraco.Core.IO.IOHelper.MapPath(Umbraco.Core.IO.SystemFiles.NotFoundhandlersConfig));
+
+ foreach (XmlNode n in customHandlers.DocumentElement.SelectNodes("notFound"))
+ {
+ var assemblyName = n.Attributes.GetNamedItem("assembly").Value;
+ var typeName = n.Attributes.GetNamedItem("type").Value;
+
+ string ns = assemblyName;
+ var nsAttr = n.Attributes.GetNamedItem("namespace");
+ if (nsAttr != null && !string.IsNullOrWhiteSpace(nsAttr.Value))
+ ns = nsAttr.Value;
+
+ LogHelper.Debug("Registering '{0}.{1},{2}'.", () => ns, () => typeName, () => assemblyName);
+
+ Type type = null;
+ try
+ {
+ //TODO: This isn't a good way to load the assembly, its already in the Domain so we should be getting the type
+ // this loads the assembly into the wrong assembly load context!!
+
+ var assembly = Assembly.LoadFrom(Umbraco.Core.IO.IOHelper.MapPath(Umbraco.Core.IO.SystemDirectories.Bin + "/" + assemblyName + ".dll"));
+ type = assembly.GetType(ns + "." + typeName);
+ }
+ catch (Exception e)
+ {
+ LogHelper.Error("Error registering handler, ignoring.", e);
+ }
+
+ if (type != null)
+ customHandlerTypes.Add(type);
+ }
+
+ _customHandlerTypes = customHandlerTypes;
+ }
+
+ public static IEnumerable CustomHandlerTypes
+ {
+ get
+ {
+ return _customHandlerTypes;
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 0a275a4e38..051977688a 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -315,8 +315,10 @@
+
+
@@ -398,7 +400,7 @@
-
+
diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs
index b4aed9339d..a6ead39ab5 100644
--- a/src/Umbraco.Web/WebBootManager.cs
+++ b/src/Umbraco.Web/WebBootManager.cs
@@ -221,7 +221,9 @@ namespace Umbraco.Web
typeof (RenderControllerFactory)
});
- LastChanceLookupResolver.Current = new LastChanceLookupResolver(new DefaultLastChanceLookup());
+ // the legacy 404 will run from within LookupByNotFoundHandlers below
+ // so for the time being there is no last chance lookup
+ LastChanceLookupResolver.Current = new LastChanceLookupResolver();
DocumentLookupsResolver.Current = new DocumentLookupsResolver(
//add all known resolvers in the correct order, devs can then modify this list on application startup either by binding to events
@@ -231,9 +233,12 @@ namespace Umbraco.Web
typeof (LookupByPageIdQuery),
typeof (LookupByNiceUrl),
typeof (LookupByIdPath),
- typeof (LookupByNiceUrlAndTemplate),
- typeof (LookupByProfile),
- typeof (LookupByAlias)
+ // these will be handled by LookupByNotFoundHandlers
+ // so they can be enabled/disabled even though resolvers are not public yet
+ //typeof (LookupByNiceUrlAndTemplate),
+ //typeof (LookupByProfile),
+ //typeof (LookupByAlias),
+ typeof (LookupByNotFoundHandlers)
});
RoutesCacheResolver.Current = new RoutesCacheResolver(new DefaultRoutesCache(_isForTesting == false));