Hello all,
As you may or may not be aware I have been building a new Umbraco starter kit called CWS Start. In this package I wanted to have a 404 page setup for the site. Currently the way to setup a 404 page is to put a node ID in the umbracosettings.config file. My only concern with this approach is that if you delete the node and recreate the node then the 404 will stop working.
So I decided to ask the Umbraco community how they do 404’s and I got a fantastic response from the community.
http://our.umbraco.org/forum/developers/extending-umbraco/43866-Alternatives-to-404-in-umbracosettingsconfig
Stefan & Lee K gave me some fantastic answers and filled me on the new Request pipeline in Umbraco and a way on how to add a ContentFinder to Umbraco, aka the new way of doing 404 handlers in Umbraco 6.1 and any other type of content finders.
Show me the code!
public class _404iLastChanceFinder : IContentFinder
{
public bool TryFindContent(PublishedContentRequest contentRequest)
{
//Check request is a 404
if (contentRequest.Is404)
{
//Get the home node
var home = contentRequest.RoutingContext.UmbracoContext.ContentCache.GetAtRoot().Single(x => x.DocumentTypeAlias == "CWS-Home");
//Get the 404 node
var notFoundNode = home.Children.Single(x => x.DocumentTypeAlias == "CWS-404");
//Set Response Status to be HTTP 404
contentRequest.SetResponseStatus(404, "404 Page Not Found");
//Set the node to be the not found node
contentRequest.PublishedContent = notFoundNode;
}
//Not sure about this line - copied from Lee K's GIST
//https://gist.github.com/leekelleher/5966488
return contentRequest.PublishedContent != null;
}
}
And then we need to register this in Umbraco on App Startup like so:
protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
//On application starting event...
//Add to the ContentFinder resolver collection our custom 404 Content Finder resolver
ContentLastChanceFinderResolver.Current.SetFinder(new _404iLastChanceFinder());
}
There are other use cases for IContentFinders and Lee K has a great little example he posted to Gist
| using Umbraco.Core; | |
| using Umbraco.Core.Services; | |
| using Umbraco.Web.Mvc; | |
| using Umbraco.Web.Routing; | |
| namespace Our.Umbraco | |
| { | |
| public class MyApplication : ApplicationEventHandler | |
| { | |
| protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) | |
| { | |
| ContentFinderResolver.Current.InsertTypeBefore<ContentFinderByNotFoundHandlers, ContentFinderForWhatever>(); | |
| base.ApplicationStarting(umbracoApplication, applicationContext); | |
| } | |
| } | |
| // the example here is to have a 'virtual url'. | |
| // this is required on a specific DocType, after @level=3 | |
| public class ContentFinderForWhatever : IContentFinder | |
| { | |
| public bool TryFindContent(PublishedContentRequest contentRequest) | |
| { | |
| if (contentRequest != null) | |
| { | |
| var path = contentRequest.Uri.GetAbsolutePathDecoded(); | |
| var parts = path.Split(new[] { '/' }, System.StringSplitOptions.RemoveEmptyEntries); | |
| if (parts.Length > 2) | |
| { | |
| var level3 = string.Concat('/', string.Join("/", parts.Take(3)), '/'); | |
| var node = contentRequest.RoutingContext.UmbracoContext.ContentCache.GetByRoute(level3); | |
| if (node.DocumentTypeAlias == "Whatever") | |
| contentRequest.PublishedContent = node; | |
| } | |
| } | |
| return contentRequest.PublishedContent != null; | |
| } | |
| } | |
| } |