6

Using Sitecore 8.1

I have two custom ItemResolvers in my site, in this order:

  • ItemResolver (The sitecore default)
  • ProductItemResolver (Determines if a product exists for a wildcard item)
  • NotFoundItemResolver (Sets a default item, if no item has been set)

The code is as follows:

ProductItemResolver.cs:

/// <summary>
/// Based on https://superruub.wordpress.com/2012/07/30/sitecore-wildcard-404-page/
/// </summary>
public class ProductItemResolver : HttpRequestProcessor
{
    public override void Process(HttpRequestArgs args)
    {
        Profiler.StartOperation("Resolve product item");
        Assert.ArgumentNotNull(args, "args");
        if (((Context.Item != null && Context.Item.Name == "*") && (Context.Database != null))
            && (args.Url.ItemPath.Length != 0)
            && Context.Item.TemplateID == SitecoreConstants.Templates.Product.Id)
        {
            //Fetch product from elastic
            var productId = args.Context.Request.Url.GetProductId();
            var catalogService = ObjectFactory.Instance.Resolve<ICatalogService>();
            var productExists = catalogService.ProductExists(productId);

            //If it is null, set Context.Item to null to trigger NotFound flow
            if (!productExists)
            {
                Context.Item = null;
            }
        }
        Profiler.EndOperation();
    }
}

NotFoundItemResolver:

/// <summary>
/// Based on https://laubplusco.net/handling-404-sitecore-avoid-302-redirects/
/// </summary>
public class NotFoundItemResolver : HttpRequestProcessor
{
    public override void Process(HttpRequestArgs args)
    {
        //Check if we even need to hande this
        if (IsValidContextItemResolved()
            || args.LocalPath.StartsWith("/sitecore")
            || args.Url.FilePath.StartsWith("/sitecore")
            || RequestIsForPhysicalFile(args.Url.FilePath))
            return;

        var siteSettingsProvider = ObjectFactory.Instance.Resolve<ISiteSettingsProvider>();
        ISiteSettings siteSettings = siteSettingsProvider.Get();

        if (siteSettings.NotFoundItem == null
            || siteSettings.NotFoundItem.Empty
            || !siteSettings.NotFoundItem.HasContextLanguage())
            return;

        Context.Item = siteSettings.NotFoundItem;
    }

    protected virtual bool IsValidContextItemResolved()
    {
        if (Context.Item == null || !Context.Item.HasContextLanguage())
            return false;
        return !(Context.Item.Visualization.Layout == null && string.IsNullOrEmpty(WebUtil.GetQueryString("sc_layout")));
    }

    protected virtual bool RequestIsForPhysicalFile(string filePath)
    {
        return File.Exists(HttpContext.Current.Server.MapPath(filePath));
    }
}

The NotFound item has a controller configured on the standardvalues of its template.

public class NotFoundController : BaseController
{
    // GET
    public override ActionResult Index()
    {
        Response.StatusCode = (int) HttpStatusCode.NotFound;
        return View("~/Views/Shared/Core/NotFound.cshtml");
    }
}

Now, if I hit a url where sitecore does not find an item, I get what I expect. I hit my NotFound controller, and render my NotFound view.

But if Sitecore resolves the wildcard item, and I set the Context.Item = null in the ProductItemResolver, then I get the layout from the wildcard item rendered, and the Context.Item.Name in the .cshtml file returns "*". Even though I just changed the item.

But the http status code of the response is 404.

What is going on here? Am I hitting some sort of caching issue?

  • Which Sitecore version are you using ? – Abhay Dhar Sep 22 '17 at 7:16
  • I would suggest to check the order in which the pipelines are getting called. It looks like Sitecore ItemResolver is being called , when it shouldnt – Abhay Dhar Sep 22 '17 at 7:30
  • 1
    MVC resolves it (again). Ref: jammykam.wordpress.com/2017/08/02/sitecore-mvc-context-item – Mark Cassidy Sep 22 '17 at 8:03
  • @MarkCassidy I think you hit it right on the money. But I think that I will change my NotFound page approach to move away from the MVC pipeline. This is the only scenario where I was using it, and probably makes sense to align with the rest of the site. If you would add your commen as an answer, I will mark that as the solution. – mortenbock Sep 22 '17 at 8:21
2

Sitecore MVC resolves it (again)

Which is both confusing and (I find) a little odd. But here's what's happening.

You patch after the regular ItemResolver and do your custom work. And you assume all is well from that point on. And normally it would be.

But Sitecore MVC adds a series of steps to the pipeline (for MVC requests, obviously), one of them being an execution of the mvc.getPageItem pipeline to build up the MVC-specific context class Sitecore.Mvc.Presentation.PageContext.

And mvc.getPageItem (you probably guessed it), sets a new value in Sitecore.Context.Page.

To work around this behaviour, one of the easiest approaches is to indicate (on HttpContext.Items for instance) that your processor has done work, and then check for this value at the end of the mvc.GetPageItem processor.

For previous and current Sitecore versions, @JammyKam has a full write up on his blog:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.