LibrarySites.Banner

Allowing Aliases and Items to Override Files with the Sitecore ASP.NET CMS

This blog posts explains how you can make the existence of an item or alias matching the requested URL override the existence of a file that also matches the requested URL in the Sitecore ASP.NET web Content Management System (CMS) and Customer Engagement Platform (CEP).

With IIS, URLs can map to files in the document root. With Sitecore, URLs can map to items in the database and to alias definition items that map to items. By default, if a file matching the requested URL exists, Sitecore processes that file, even if the request also matches an alias or an item. Before going further, first I would try to avoid creating these types of conflicts. If an item exists, no file, subdirectory, alias, or anything else should exist at that path. I realize this may not always be possible.

This httpRequestBegin pipeline contains the relevant logic, specifically in these three processors that appear in this order:

  • AliasResolver: If the URL maps to an alias, sets the context item to the item specified by that alias.
  • FileResolver: If the URL maps to a file (or a subdirectory that contains a default.aspx file), sets Sitecore.Context.Page.FilePath to the path to that file.
  • ItemResolver: If nothing has set the context item and the URL maps to an item, sets the context item to that item.

There is actually a DefaultResolver between AliasResolver and FileResolver, but I think this applies in very limited cases and we can ignore it for now. If this solution raises issues, this might be something to reconsider.

At the end of the httpRequestBegin pipeline, if Sitecore.Context.Page.FilePath contains a value (which could have been set by AliasResolver (in the case of aliases to external URLs), FileResolver (as described previously), or LayoutResolver (which comes after ItemResolver and could set FilePath based on the layout specified in the context item), the ExecuteRequest processor rewrites the requested URL to that value.

To prevent Sitecore from rewriting the URL when it maps to both an alias and an item, you can override the FileResolver processor to not set Sitecore.Context.Page.FilePath if the context item is not empty, or you can override ExecuteRequest to not rewrite the URL in that case. The first way is probably easier: just create a class that inherits from FileResolver and in the Process() method, only call the Process() method in the base class if Sitecore.Context.Item is not null.

namespace Sitecore.Sharedsource.Pipelines.HttpRequest
{
  using S = Sitecore;
  
  public class FileResolver : S.Pipelines.HttpRequest.FileResolver
  {
    public override void Process(S.Pipelines.HttpRequest.HttpRequestArgs args)
    {
      if (S.Context.Item == null)
      {
        base.Process(args);
      }
    }
  }
}

You can use a Web.config file such as the following (/App_Config/Include/ Sitecore.Sharedsource.FileResolver.config in my case) to enable this processor:

<configuration xmlns:patch="https://www.sitecore.com/xmlconfig/">
  <sitecore>
    <pipelines>
      <httpRequestBegin>
        <processor type="Sitecore.Pipelines.HttpRequest.FileResolver, Sitecore.Kernel">
          <patch:attribute name="type">Sitecore.Sharedsource.Pipelines.HttpRequest.FileResolver,Sitecore.Sharedsource</patch:attribute>
        </processor>
      </httpRequestBegin>
    </pipelines>
  </sitecore>
</configuration>

To get the existence of an item at a path to override the existence of a file at that path, you should be able to implement a solution such as this and move the ItemResolver processor before the FileResolver processor.

Because the AliasResolver processor comes before the ItemResolver processor in the httpRequestBegin pipeline and sets the context item if the URL matches an alias, and because the ItemResolver processor does nothing if something has set the context item, the existence of an alias at a path overrides the existence of an item at the same path. If you want the existence of an item to override the existence of an item, first I would say that you should not allow both an alias and an item at the same path. That said, it should be possible to override FileResolver as described in this post, override the AliasResolver to do nothing if something has already set the context item (similar to the way this post overrides FileResolver), and move the ItemResolver before the AliasResolver in the httpRequestBegin pipeline.

Resources