6

I have a custom item resolver where I am trying to set the context item based on the path in the url (this is for a re-written url). I've patched this in after Sitecores ItemResolver and it runs fine. However when my page loads the context item doesn't seem to be set correctly when I attached the debugger and none of my renderings get the correct item. It looks similar to this:

   public class CustomUrlResolver : HttpRequestProcessor
   {
      public override void Process(HttpRequestArgs args)
      {
         Assert.ArgumentNotNull(args, "args");

         /*In Case Sitecore has mapped the item, do not do anything and simply return*/
         if (Context.Item != null || Context.Database == null || args.Url.ItemPath.Length == 0) return;

         /*If not, Check for item based on the FilePath*/
         Item contextItem = CustomUrlManager.GetItemByFilePath(args.Url.FilePath);
         if (contextItem != null) Context.Item = contextItem;
      }
   }

As a test I tried to see if I could set the context item in one of my controller renderings and I can force the context item like so:

Item contextItem = CustomUrlManager.GetItemByFilePath("/a-path/my-item", Context.Database);
if (contextItem != null)
{
    Context.Item = contextItem;
    rc.RenderingContext.Current.Rendering.Item = contextItem;
    rc.RenderingContext.Current.ContextItem = contextItem;
    rc.RenderingContext.Current.PageContext.Item = contextItem;
}

Other components further down the page then pick up the correct context item However it doesn't seem to work correctly from a httpRequestBegin Pipeline.

I've tried moving when my pipeline executes and also removing any other custom Pipelines we have but can't seem to get the context item to be set correctly.

I am not sure if it's because we are using MVC and Glass and there is something I'm missing here but any ideas would be welcome?

Other info: Sitecore 8.1 update 2, MVC, Glass, url rewrite module: https://marketplace.sitecore.net/Modules/Url_Rewrite.aspx

  • 1
    From what I remember, one of the mvc processors overrides Sitecore.Context.Item. – Marek Musielak Mar 24 '17 at 14:35
  • Thanks Marek, I'm guessing maybe SetupPageContext or GetPageItem.GetFromOldContext / GetFromRouteUrl. I'll do some more digging and see. If you remember which one though please let me know. – Adam Seabridge Mar 24 '17 at 14:46
9

The Pipeline that you want to focus in on is the mvc.getPageItem pipeline.

<mvc.getPageItem patch:source="Sitecore.Mvc.config">
  <processor type="Sitecore.Mvc.Pipelines.Response.GetPageItem.SetLanguage, Sitecore.Mvc"/>
  <processor type="Sitecore.Mvc.Pipelines.Response.GetPageItem.GetFromRouteValue, Sitecore.Mvc"/>
  <processor type="Sitecore.Mvc.Pipelines.Response.GetPageItem.GetFromRouteUrl, Sitecore.Mvc"/>
  <processor type="Sitecore.Mvc.Pipelines.Response.GetPageItem.GetFromOldContext, Sitecore.Mvc"/>
  <processor type="Sitecore.ContentTesting.Mvc.Pipelines.Response.GetPageItem.PageLevelTestVariantResolver, Sitecore.ContentTesting.Mvc" patch:source="Sitecore.ContentTesting.Mvc.config"/>
  <processor type="Sitecore.ContentTesting.Mvc.Pipelines.Response.GetPageItem.ContentTestVariantResolver, Sitecore.ContentTesting.Mvc" patch:source="Sitecore.ContentTesting.Mvc.config"/>
</mvc.getPageItem>

The processor GetFromOldContext will set the PageItem to Context.Item only if the previous processors haven't already identified an item.

  public class GetFromOldContext : GetPageItemProcessor
  {
    public override void Process(GetPageItemArgs args)
    {
      Assert.ArgumentNotNull((object) args, "args");
      if (args.Result != null)
        return;
      args.Result = this.ResolveItem(args);
    }

    protected virtual Item ResolveItem(GetPageItemArgs args)
    {
      return Context.Item;
    }
  }

Recommedation

Create a processor for this pipeline that comes after either GetFromRouteUrl or GetFromOldContext to determine whether you want to continue using the Page Item found, or use from the Custom Item Resolver.

PageContext Does Overwrite Context.Item

A little more digging found that the PageContext has a Property for Item. When the PageContext.Item is fetched for the first time, it calls a method GetItem() which ends up calling the mvc.getPageItem pipeline.

If the ID of the Context.Item doesn't match the ID returned from this pipeline, then it resets the value of Context.Item to that of the Result from the pipeline.

protected virtual Item GetItem()
{
  using (new RecursionPreventer("GetItem", this.getItemFlag))
  {
    using (TraceBlock.Start("Get item for {0}.".FormatWith((object) typeof (PageContext))))
    {
      Item obj = PipelineService.Get().RunPipeline<GetPageItemArgs, Item>("mvc.getPageItem", new GetPageItemArgs(), (Func<GetPageItemArgs, Item>) (args => args.Result));
      if (obj != null)
      {
        if (Context.Language == (Language) null || Context.Language != obj.Language)
          Context.Language = obj.Language;
        if (Context.Item == null || Context.Item.ID != obj.ID)
          Context.Item = obj;
        return obj;
      }
      Tracer.Info((object) "Using Sitecore.Context.Item.");
      return Context.Item;
    }
  }
}
  • 1
    Great, thanks Pete! I've had a play around with this and nearly have it all working now. I appreciate your help with this. – Adam Seabridge Mar 24 '17 at 17:35
2

If httpRequestBegin pipeline is base place where you are resolving the item, you can also re-patch the configuration and move GetFromOldContext to the first position

<mvc.getPageItem>
  <processor type="Sitecore.Mvc.Pipelines.Response.GetPageItem.GetFromOldContext, Sitecore.Mvc">
    <patch:delete />
  </processor>
  <processor patch:after="processor[@type='Sitecore.Mvc.Pipelines.Response.GetPageItem.SetLanguage, Sitecore.Mvc']" type="Sitecore.Mvc.Pipelines.Response.GetPageItem.GetFromOldContext, Sitecore.Mvc"/>
</mvc.getPageItem>

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.