Search code examples
sitecoresitecore8sitecore7.2sitecore-mvc

Change sitecore item without redirect


I have a custom pipeline processor inserted after ItemResolver in which I overwrite the current context item with a new item selected by the content editor from a droplink.

If I go to that dynamic item via a normal request through my website and through my processor and i change my context item, it will stil render the same item:

public override void Process(HttpRequestArgs args)
{
  // some code
  Context.Item = dropLink.TargetItem;
}

Strangely, if I issue a request via the item API, sitecore changes the item successfully

//api call
Context.Item = Context.Database.SelectSingleItem("fast:/sitecore/content/mysite/dynamicitem");

Here is my config file:

<pipelines>
 <httpRequestBegin>
   <processor  patch:after="* @type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']"  type="MyDll.Web.Pipelines.LandingPageResolver,MyDll.Web" />
 </httpRequestBegin>
</pipelines>

Solution

  • Since you are using MVC the item is resolved (again) using a different set of pipelines, so you need to patch into there instead.

    The GetFromRouteUrl processor in the mvc.getPageItem pipeline sets args.Result to the item matching the requested URL which is then eventually set to Context.Item, so it essentially resets the item back to the "correct" item based on the URL and that overwrites the changes you made earlier.

    You need to add a need processor to the mvc.getPageItem with some logic to check if the context item has already been resolved.

    Update your code in the ItemResolver and store a boolean to indicate that you have already resolved using custom logic, this saves having to run the resolving logic twice:

    public override void Process(HttpRequestArgs args)
    {
      // some code
      Context.Item = dropLink.TargetItem;
      Context.Items["custom::ItemResolved"] = true;
    }
    

    Create a new Class that checks if your custom logic has already resolved the item:

    public class CheckItemResolved: GetPageItemProcessor
    {
      public override void Process(GetPageItemArgs args)
      {
        if (args.Result == null)
        {
            var resolved = Sitecore.Context.Items["custom::ItemResolved"];
            if (MainUtil.GetBool(resolved, false))
            {
                // item has previously been resolved
                args.Result = Sitecore.Context.Item;
            }
        }
    
        return;
      }
    }
    

    And then patch this in:

    <pipelines>
      <mvc.getPageItem>
        <processor type="MyProject.Custom.Pipelines.CheckItemResolved, MyProject.Custom"
            patch:before="*[@type='Sitecore.Mvc.Pipelines.Response.GetPageItem.GetFromRouteUrl, Sitecore.Mvc']" />
      </mvc.getPageItem>
    </pipelines>
    

    The pipeline immediately after is GetFromFromUrl() which would normally set args.Result by re-resolving the Item. By setting it back to Context.Item that processor will break out early and leave your previous logic alone.

    You can find more details about MVC and Pipelines in the documentation.