Mixing Sublayout with Rendering – Webforms with MVC request

Do you have following symptoms in your Sitecore Project?

  • You have legacy sublayouts (.ascx) based components and cannot change them to MVC Controller renderings or View Renderings due to a tight deadline or project budget
  • You want to switch to MVC implementation from Webforms but have doubts if MVC and Webforms can work together or not.
  • You might have both implementation but want to combine both the approach in a single request.
  • Lastly you want your sublayouts to work individually as they are already being referenced heavily but want them to be used in Sitecore MVC.

If you are looking for a cure on above symptoms, this blog post might be able to help you with it. Well i am not a Doctor though! but yes I am Sitecore developer trying to share experience.

Officially Sitecore do not recommend or support to mingle Webforms and MVC in a single request. Either it can be a full Webforms or a full MVC request. You cannot use a layout(.aspx) file and insert a controller rendering or view rendering on the presentation details of your page / standard values.

HUH! I too had the same understanding until I came upon a requirement where I have to work upon mixing the request. There are a lot of good brains around for Sitecore Community and I was able to find a solution for the requirement where-in I had a page being build up with Contoller rendering, but that in turn need to call a Sublayout. The reasons for doing this were straightforward we cannot re-write all our Sublayouts and convert them in Renderings due to project budget and deadlines.

I will share both approaches and lastly will share my implementation as I had to work on something extra due to an exceptional case.
1) Using Sitecore MVC components on WebForms pages

The solution is nicely mentioned on the blog post by Charlie Turano (HedgeHog) and we are all aware about the HedgeHog contribution to Sitecore Community. So check this post out if you are looking to call MVC components in your Webform request.

2) BissTalk Sitecore Synergy

This github solution allows to render Sublayouts onto an MVC request. BissTalk Sitecore Synergy detects all controls on the presentation details of a page and switches all the sublayouts to mvc renderings.

I will not go in details of the above two solutions as they are already well described in the blog posts.

The Problem

Challenge I faced was we have a sublayout which in turn was calling another inner sublayout dynamically from code behind file. We have a SlideShow sublayout which was added to the presentation details of a page. The slide show can have,

  1. Images
  2. Videos
  3. YouTube Vidoes

So based on the datasource template we were calling sublayouts dynamically

[code language=”xml”]
if (item.TemplateID.Equals(new ID(ImageSlideItem.TemplateId)))
{
slideSublayout.Path = "~/Common/Sublayouts/PageElements/Image/Image.ascx";
}
else if (item.TemplateID.Equals(new ID(VideoSlideItem.TemplateId)))
{
slideSublayout.Path = "~/Common/Sublayouts/PageElements/Video/HostedVideo.ascx";
}
else if (item.TemplateID.Equals(new ID(YouTubeVideoSlideItem.TemplateId)))
{
slideSublayout.Path = "~/Common/Sublayouts/PageElements/Video/YouTubeVideo.ascx";
}

[/code]

The other challenge was the sublayout should work in a normal webform request too as they were already being used on other pages.

So even though we implemented the solution suggested by Biss Talk our sublayout was not getting rendered.

Solution

We created an extension method on the Sublayout to get its HTML and inject it into the MVC request. Intresting isn’t it? Keep reading futher for the solution.

Dummy Page Class

Created a DummyPage calss inheriting form System.Web.UI.Page, override the Render method to get the required HTML, no big stuff here

[code language=”xml”]
public class DummyPage : Page
{
/// <summary>
/// Gets the rendered HTML result.
/// </summary>
/// <value>
/// The resulting HTML.
/// </value>
public string Result { get; private set; }

/// <summary>
/// Initializes the <see cref="System.Web.UI.HtmlTextWriter" /> object and calls on the child controls of the <see cref="System.Web.UI.Page" /> to render.
/// </summary>
/// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter" /> that receives the page content.</param>
protected override void Render(HtmlTextWriter writer)
{
var buffer = new StringWriter();
var stringWriter = new HtmlTextWriter(buffer);
base.Render(stringWriter);
Result = buffer.ToString();
}
}

[/code]
Creating SublayoutExtension Class

Next was to create an Extension Method on Sublayout.
[code language=”xml”]
public static class SubLayoutExtension
{
public static string RenderSublayoutHTML(this Sublayout subLayout)
{
string retHTML = string.Empty;

var page = new DummyPage();

if (HttpContext.Current.Items.Contains("ismvc"))
{
var userControl = page.LoadControl(subLayout.Path);
subLayout.Controls.Add(userControl);

}
page.Controls.Add(subLayout);
retHTML = ExecutePage(page);

return retHTML;
}
private static string ExecutePage(DummyPage page)
{
page.ProcessRequest(HttpContext.Current);
return page.Result;
}
}
[/code]
Code to call the extension method.

[code language=”xml”]
var item = e.Item.DataItem as Item;
if (item == null) return;

var slideImage = e.Item.FindControl("slideImage") as Literal;
if (slideImage == null) return;

Sublayout slideSublayout = new Sublayout();
slideSublayout.DataSource = item.Paths.FullPath;

if (item.TemplateID.Equals(new ID(ImageSlideItem.TemplateId)))
{
slideSublayout.Path = "~/Common/Sublayouts/PageElements/Image/Image.ascx";
}
else if (item.TemplateID.Equals(new ID(VideoSlideItem.TemplateId)))
{
slideSublayout.Path = "~/Common/Sublayouts/PageElements/Video/HostedVideo.ascx";
}
else if (item.TemplateID.Equals(new ID(YouTubeVideoSlideItem.TemplateId)))
{
slideSublayout.Path = "~/Common/Sublayouts/PageElements/Video/YouTubeVideo.ascx";
}
slideImage.Text = slideSublayout.RenderSublayoutHTML();
[/code]
So the HTML was finally injected into a literal control that was being used inside a Repeater ItemDataBound.

The coolest part of this implementation was it worked with the Experience Editor mode as well.

A special thanks to John Kurtis and Andy Cohen from Horizontal Integration with whom we worked upon for such a solution.