U4-1441 - refactor (fix) legacy NotFoundHandler support

This commit is contained in:
Stephan
2013-02-03 14:34:04 -01:00
parent eaa36a248c
commit 95df864d01
5 changed files with 125 additions and 85 deletions

View File

@@ -7,15 +7,11 @@ using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using umbraco;
using umbraco.interfaces;
namespace Umbraco.Web.Routing
{
/// <summary>
/// Provides an implementation of <see cref="IContentFinder"/> that runs the legacy 404 logic.
/// </summary>
/// <remarks>Should be used as a last chance finder.</remarks>
internal class ContentFinderByLegacy404 : IContentFinder
{
/// <summary>
@@ -25,8 +21,9 @@ namespace Umbraco.Web.Routing
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
public bool TryFindDocument(PublishedContentRequest pcr)
{
LogHelper.Debug<ContentFinderByLegacy404>("Looking for a page to handler 404.");
LogHelper.Debug<ContentFinderByLegacy404>("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);
@@ -51,6 +48,7 @@ namespace Umbraco.Web.Routing
}
pcr.PublishedContent = content;
pcr.SetIs404();
return content != null;
}
}

View File

@@ -21,9 +21,6 @@ namespace Umbraco.Web.Routing
// at the moment we load the legacy INotFoundHandler
// excluding those that have been replaced by proper finders,
// and run them.
//
// code from requestHandler.handle404 has been moved over to
// the new ContentFinderByLegacy404 finder.
/// <summary>
/// Tries to find and assign an Umbraco document to a <c>PublishedContentRequest</c>.
@@ -32,34 +29,71 @@ namespace Umbraco.Web.Routing
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
public bool TryFindDocument(PublishedContentRequest docRequest)
{
docRequest.PublishedContent = HandlePageNotFound(docRequest);
HandlePageNotFound(docRequest);
return docRequest.HasPublishedContent;
}
#region Copied over from presentation.requestHandler
#region Copied over and adapted from presentation.requestHandler
//FIXME: this is temporary and should be obsoleted
IPublishedContent HandlePageNotFound(PublishedContentRequest docRequest)
void HandlePageNotFound(PublishedContentRequest docRequest)
{
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Running for url='{0}'.", () => docRequest.Uri.AbsolutePath);
//XmlNode currentPage = null;
IPublishedContent currentPage = null;
var url = NotFoundHandlerHelper.GetLegacyUrlForNotFoundHandlers();
foreach (var handler in GetNotFoundHandlers())
{
IContentFinder finder = null;
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}'.", () => handler.GetType().FullName);
// replace with our own implementation
if (handler is global::umbraco.SearchForAlias)
finder = new ContentFinderByUrlAlias();
else if (handler is global::umbraco.SearchForProfile)
finder = new ContentFinderByProfile();
else if (handler is global::umbraco.SearchForTemplate)
finder = new ContentFinderByNiceUrlAndTemplate();
else if (handler is global::umbraco.handle404)
finder = new ContentFinderByLegacy404();
if (finder != null)
{
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Replace handler '{0}' by new finder '{1}'.", () => handler.GetType().FullName, () => finder.GetType().FullName);
if (finder.TryFindDocument(docRequest))
{
// do NOT set docRequest.PublishedContent again here as
// it would clear any template that the finder might have set
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Finder '{0}' found node with id={1}.", () => finder.GetType().FullName, () => docRequest.PublishedContent.Id);
if (docRequest.Is404)
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Finder '{0}' set status to 404.", () => finder.GetType().FullName);
return;
}
}
// else it's a legacy handler, run
if (handler.Execute(url) && handler.redirectID > 0)
{
//currentPage = umbracoContent.GetElementById(handler.redirectID.ToString());
currentPage = docRequest.RoutingContext.PublishedContentStore.GetDocumentById(
docRequest.PublishedContent = docRequest.RoutingContext.PublishedContentStore.GetDocumentById(
docRequest.RoutingContext.UmbracoContext,
handler.redirectID);
// FIXME - could it be null?
if (!docRequest.HasPublishedContent)
{
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found node with id={1} which is not valid.", () => handler.GetType().FullName, () => handler.redirectID);
break;
}
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found node with id={1}.", () => handler.GetType().FullName, () => handler.redirectID);
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found valid node with id={1}.", () => handler.GetType().FullName, () => handler.redirectID);
if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404)
{
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' set status code to 404.", () => handler.GetType().FullName);
docRequest.Is404 = true;
}
//// check for caching
//if (handler.CacheUrl)
@@ -78,60 +112,6 @@ namespace Umbraco.Web.Routing
break;
}
}
return currentPage;
}
static IEnumerable<Type> _customHandlerTypes = null;
static readonly object CustomHandlerTypesLock = new object();
IEnumerable<Type> InitializeNotFoundHandlers()
{
// initialize handlers
// create the definition cache
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Registering custom handlers.");
var customHandlerTypes = new List<Type>();
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;
// skip those that are in umbraco.dll because we have replaced them with finders
if (assemblyName == "umbraco")
continue;
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<ContentFinderByNotFoundHandlers>("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<ContentFinderByNotFoundHandlers>("Error registering handler, ignoring.", e);
}
if (type != null)
customHandlerTypes.Add(type);
}
return customHandlerTypes;
}
IEnumerable<INotFoundHandler> GetNotFoundHandlers()
@@ -139,15 +119,9 @@ namespace Umbraco.Web.Routing
// instanciate new handlers
// using definition cache
lock (CustomHandlerTypesLock)
{
if (_customHandlerTypes == null)
_customHandlerTypes = InitializeNotFoundHandlers();
}
var handlers = new List<INotFoundHandler>();
foreach (var type in _customHandlerTypes)
foreach (var type in NotFoundHandlerHelper.CustomHandlerTypes)
{
try
{

View File

@@ -23,7 +23,6 @@ namespace Umbraco.Web.Routing
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
public bool TryFindDocument(PublishedContentRequest docRequest)
{
IPublishedContent node = null;
if (docRequest.Uri.AbsolutePath != "/") // no alias if "/"

View File

@@ -3,14 +3,24 @@ 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
internal 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"
@@ -70,5 +80,60 @@ namespace Umbraco.Web.Routing
httpContext.Items[ContextKey] = tmp;
return tmp;
}
}
static IEnumerable<Type> _customHandlerTypes = null;
static void InitializeNotFoundHandlers()
{
// initialize handlers
// create the definition cache
LogHelper.Debug<NotFoundHandlerHelper>("Registering custom handlers.");
var customHandlerTypes = new List<Type>();
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<NotFoundHandlerHelper>("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<NotFoundHandlerHelper>("Error registering handler, ignoring.", e);
}
if (type != null)
customHandlerTypes.Add(type);
}
_customHandlerTypes = customHandlerTypes;
}
public static IEnumerable<Type> CustomHandlerTypes
{
get
{
return _customHandlerTypes;
}
}
}
}

View File

@@ -189,7 +189,9 @@ namespace Umbraco.Web
typeof (RenderControllerFactory)
});
ContentLastChanceFinderResolver.Current = new ContentLastChanceFinderResolver(new ContentFinderByLegacy404());
// the legacy 404 will run from within ContentFinderByNotFoundHandlers below
// so for the time being there is no last chance finder
ContentLastChanceFinderResolver.Current = new ContentLastChanceFinderResolver();
ContentFinderResolver.Current = new ContentFinderResolver(
//add all known resolvers in the correct order, devs can then modify this list on application startup either by binding to events
@@ -199,9 +201,11 @@ namespace Umbraco.Web
typeof (ContentFinderByPageIdQuery),
typeof (ContentFinderByNiceUrl),
typeof (ContentFinderByIdPath),
typeof (ContentFinderByNiceUrlAndTemplate),
typeof (ContentFinderByProfile),
typeof (ContentFinderByUrlAlias),
// these will be handled by ContentFinderByNotFoundHandlers
// so they can be enabled/disabled even though resolvers are not public yet
//typeof (ContentFinderByNiceUrlAndTemplate),
//typeof (ContentFinderByProfile),
//typeof (ContentFinderByUrlAlias),
typeof (ContentFinderByNotFoundHandlers)
});