0

I am working on programatically rendering an item to html in code.

I found this question https://sitecore.stackexchange.com/a/6256/1133 which almost serves the purpose of my request, except it isn't rendering nested renderings for me. My item has 4 renderings like so:

  • SimulationContainer (placeholder: simulator)
  • Picker (placeholder: /simulator/simulatorcomponents)
  • SimulatorTeaser (placeholder: /simulator/simulatorcomponents)
  • Simulator (placeholder: /simulator/simulatorcomponents)

Only the SimulationContainer rendering is being output to html.

Is there a way that I can modify the code from the linked question to include the nested renderings?

The code I've used from the questions is as follows:

const string itemPath = "/sitecore/content/Site/Home/Test";
var item = Sitecore.Context.Database.GetItem(itemPath);

var pageContext = new PageContext
{
    RequestContext = System.Web.HttpContext.Current.Request.RequestContext,
    Item = item
};

ContextService.Get().Push(pageContext);

var pageDefinition = pageContext.PageDefinition;
var getPageRenderingArgs = new GetPageRenderingArgs(pageDefinition);

PipelineService.Get().RunPipeline("mvc.getPageRendering", getPageRenderingArgs);

var rendering = getPageRenderingArgs.Result;
var textWriter = new StringWriter();
var renderRenderingArgs = new RenderRenderingArgs(rendering, textWriter);

PipelineService.Get().RunPipeline("mvc.renderRendering", renderRenderingArgs);
ContextService.Get().Pop<PageContext>();

return textWriter.ToString();
3
  • I'm not sure of the appropriate way to handle this situation on StackExchange but I found a different question that had an answer that worked for me. This answer (sitecore.stackexchange.com/a/3589/1133) did exactly what I needed it to in a very simple fashion.
    – Iceape
    Apr 6, 2018 at 13:02
  • Hi @Iceape would you remember how did you solve the nesting issue? I've done the implementation in that link you shared but nesting is an issue, I just get all renderings stacked. Thanks!
    – jgondev
    May 23, 2020 at 16:54
  • Hi @jgondev I do still have the code that we ended up using. I don't remember much about it so can't really explain how it works or why we did what we did. It looks like it's pretty different from the code posted in this question and the code I linked to in my comment though. I uploaded it to a dotnetfiddle here for you dotnetfiddle.net/e6OlTz I think the part that preserved nesting is the last method GetRenderings
    – Iceape
    May 29, 2020 at 8:04

1 Answer 1

0

I don't think that it will be easy to modify code above. Problem is that you will need to run all Sitecore pipelines and processors for all renderings.

I can suggest you different approach, how I did something similar some time ago. I wrote extension for Sitecore.MVC that allowed to get by AJAX request not full item presentation, but only part. It allowed to refresh only part of page. E.g., it could be used for refreshing basket on some commerce site without loading whole page.

Sequence, how to do it:

  1. Create empty layout
  2. Add your handler that will process request
  3. Move presentation from Item layout details to some "virtual" presentation detail. Rendering that should be rendered should be placed in placeholder on empty layout.
  4. Run default Sitecore pipelines to perform rendering.

Idea is to place rendering that you need from real item presentation to new item presentation that is based on empty layout and then call default Sitecore pipelines. This approach will render your rendering and all nested renderings, because default Sitecore pipelines are used. Even more, if there is some personalization or A/B testing, it still will work.

Here is code that does this stuff:

  //The second parameter we need to pass is the PresentationId if not present the query if not valid -> don't continue  
  var presentationId = {UID of presentation item that should be rendered}
  if (string.IsNullOrEmpty(presentationId))
  {
    return;
  }

  //If the current item is null return  
  if (Sitecore.Context.Item == null)
  {
    return;
  }

  //Let's resolve the sublayout  
  try
  {
    //Get the list of rendering for the current item  
    var renderings = args.PageDefinition.Renderings;
    //If found  
    if (renderings != null && renderings.Any())
    {
      //Get the first rendering corresponding to the requested one  
      var rendering = renderings.First(sublayout => sublayout.RenderingItem.ID.ToString().Equals(presentationId));

      if (rendering != null)
      {
        args.PageDefinition.Renderings.Remove(rendering);
        //Put this rendering into ajax layout  
        rendering.Placeholder = Constants.Strings.AjaxPlaceholderKey;

        rendering.LayoutId = new Guid(Constants.IDs.AjaxEmptyLayout);
        var layout = renderings.First(x => x.RenderingType == "Layout");
        if (layout != null)
        {
          args.PageDefinition.Renderings.Remove(layout);
          for ( int i=0; i< args.PageDefinition.Renderings.Count; i++)
          {
            args.PageDefinition.Renderings[i].Placeholder =
              args.PageDefinition.Renderings[i].Placeholder.Split('/').Last();
            args.PageDefinition.Renderings[i].LayoutId =
              new Guid(Constants.IDs.AjaxEmptyLayout);
          }
          layout.LayoutId = new Guid(Constants.IDs.AjaxEmptyLayout);
          var getRedererArgs = new GetRendererArgs(new Rendering());
          getRedererArgs.LayoutItem =
            Sitecore.Context.Database.GetItem(Constants.IDs.AjaxEmptyLayout);

          if (rendering.Renderer is Sitecore.Mvc.Presentation.ControllerRenderer)
          {
            RouteValueDictionary routeValueDictionary = new RouteValueDictionary();
            foreach (var key in  HttpContext.Current.Request.QueryString.AllKeys.Select(x=> x.ToString()))
            {
              routeValueDictionary.Add(key, HttpContext.Current.Request.QueryString[key]);
            }
            ((Presentation.ControllerRenderer)rendering.Renderer).routeValueDictionary = routeValueDictionary;
          }
          layout.Renderer = PipelineService.Get().RunPipeline<GetRendererArgs, Renderer>(PipelineNames.GetRenderer, getRedererArgs, a => a.Result);

          args.PageDefinition.Renderings.Add(layout);
          args.PageDefinition.Renderings.Add(rendering);
        }
      }
    }
  }
  catch (Exception exception)
  {
    Log.Warn("Failed to render presentation", exception, this);
  }

To see more in details, you can review this GitHub repository.

2
  • This looks useful, thanks! Pipelines and processors are unfamiliar territory for me, but I'm trying to learn and understand this as best I can. Does 'presentationID' represent a page item or a controller rendering?
    – Iceape
    Apr 5, 2018 at 16:47
  • @Iceape It is controller rendering ID.
    – Anton
    Apr 5, 2018 at 17:01

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