Tag: Pipelines

Pipelines - remember the big picture

Sitecore pipelines are great. With them you can relatively easily add and remove functionality as you wish. Pipelines like httpRequestBegin, httpRequestProcessed and mvc.beginRequest are also really useful if you need some logic to run on a page load that shouldn't really be part of a rendering. This could be anything from login checks to updating the way 404 pages are returned. However you do need to remember the big picture of what you are changing.

Pipelines don't just effect the processes of the website your building, Sitecore uses them too. That means when you add a new processor to the httpRequestBegin pipeline, that's going to effect every request in the admin CMS too. Just checking the context item also isn't enough as some things. e.g. opening a node in a tree view, will have the context of the node you clicked on!

Adding this snippet of code to the beginning of your process should keep you safe though.

using Sitecore.Diagnostics;
using Sitecore.Pipelines.HttpRequest;
using Sitecore;
using Sitecore.SecurityModel;

namespace CustomPiplelineNamespace
{
  public class CustomPipeline : HttpRequestProcessor
  {
      public override void Process(HttpRequestArgs args)
      {
          //Check args isn't null
          Assert.ArgumentNotNull(args, "args");
          //Check we have a site
          if (Context.Site == null)
              return;
          //Check the sites domain isn't one for sitecore
          if (Context.Site.Domain != DomainManager.GetDomain("sitecore"))
              return;
          //Check that we're not in a redirect
          if (args.Url.FilePathWithQueryString.ToUpperInvariant().Contains("redirected=true".ToUpperInvariant()))
              return;
          //Check that we're not in the page editor
          if (Context.PageMode.IsPageEditor)
              return;

          // DO CODE
      }
  }
}

Updating the response headers on your 404 Page in Sitecore

A few weeks ago I blogged about how to create a custom 404 Page in Sitecore. Following on from that, one thing you may notice in the response header of your 404 Page is the status code is 200 Ok, rather than 404 Page not found.

When Sitecore can't find a page what actually happens is a 302 redirect is issued to the page not found page, which as its an ordinary page will return a 200 Ok. Thankfully Google is actually quite good at detecting pages a being 404's even when they return the wrong status code, but it would be better if our sites issues the correct headers.

Method 1

The simplest solution is to create a view rendering with the following logic and place it somewhere on your page not found page. This will update the response headers with the correct values.

@{
    Response.TrySkipIisCustomErrors = true;
    Response.StatusCode = 404;
    Response.StatusDescription = "Page not found";
}

However personally I don't think this a particularly neat solution. The contents of a view should really be left for what's going in a page rather than interfering with its headers, even if it does have access to the Response object.

Method 2

Rather than using a view my solution is to add some code to the httpRequestEnd pipeline that will check the context items Id against a setting where we will store the Id of the 404 page item in Sitecore and if the two match then update the response header.

The solution will look like this

Pipeline logic

using Sitecore.Configuration;
using Sitecore.Data;
using Sitecore.Pipelines.HttpRequest;

namespace Pipelines.HttpRequest
{
  public class PageNotFoundResponseHeader : HttpRequestProcessor
  {
      private static readonly string PageNotFoundID = Settings.GetSetting("PageNotFound");

      public override void Process(HttpRequestArgs args)
      {
          if (Sitecore.Context.Item != null && Sitecore.Context.Item.ID == new ID(PageNotFoundID))
          {
              args.Context.Response.TrySkipIisCustomErrors = true;
              args.Context.Response.StatusCode = 404;
              args.Context.Response.StatusDescription = "Page not found";
          }
      }
  }
}

Patch config file

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
  <pipelines>
    <httpRequestEnd>
      <processor
        patch:after="processor[@type='Sitecore.Pipelines.PreprocessRequest.CheckIgnoreFlag, Sitecore.Kernel']"
        type="Pipelines.HttpRequest.PageNotFoundResponseHeader, MyProjectName"  />
    </httpRequestEnd>
  </pipelines>
  <settings>
    <!-- Page Not Found Item Id -->
    <setting name="PageNotFound" value="ID of 404 Page" />
  </settings>
</sitecore>
</configuration>

What's the TrySkipIisCustomErrors property

Quite simply this stops a scenario where you end up on IIS's 404 page rather than your own. If you don't set this, when you update the header status code to 404, IIS likes to return the page from it's settings rather than continuing with your own.