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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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; | |
| } | |
| } | |
| } |