How To Manually Render An Episerver Block In Code

This post is another rare case example and, as the usual disclaimer, 99% of the time you will never need to do this.  The information in this article is a working that may be required in exception circumstances.  Situations like custom caching or rendering of content spring to mind.  This should not be used for getting around routing issues, like form post back in blocks.

In a recent project, I needed to create a custom cache layer in my architecture.  This custom cache meant only rendering certain blocks within a content area at specific times.  In the majority of situations the easy way to render a block is to use the PropertyFor HTML helper provided by Episerver.

In my situation, I wanted to write out specific blocks based within an ActionFilterAttribute.  Obviously, the first problem you face in this situation is how to get Episerver to render the block?  In the attribute, or, a controller, for example, you do not have access to the HTM

Creating A HTMLHelper Instance From A Attribute

In the attribute situation, you’re lucky to still have access to a lot of the page context, so life isn’t too hard.  If you inherit from ActionFilterAttribute, you will need to implement the OnActionExecuting and OnResultExecuted. Both these methods get passed the ActionExecutingContext, which is exactly the parameter you need to new-up a HTML-Helper.

public class Attribute : ActionFilterAttribute, IExceptionFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
using (var textWriter = new StringWriter())
{
var htmlHelper = CreateHtmlHelper(filterContext.Controller, textWriter);
}
}
}
private HtmlHelper CreateHtmlHelper(ControllerBase controller, StringWriter textWriter)
{
var viewContext = new ViewContext(
controller.ControllerContext,
new WebFormView(controller.ControllerContext, "tmp"),
controller.ViewData,
controller.TempData,
textWriter
);
return new HtmlHelper(viewContext, new ViewPage());
}

Let’s talk through what’s going on to create a new HTMLHelper instance.  We wrap the initialization in a StringWriter. When we come to render the Episerver content later, Episerver writes the output to a stream rather than return the HTML in a string.  When we write the data out we will need a way to capture the HTML.  We also use the filterContext passed in via the overload.

The HTMLHelper takes a ViewContext and a ViewPage, in this instance we need to create a new context. Using the ActionExecutingContext instance, we pass in the controller context, the view data and temp data. We pass in our new StringWriter and create a new WebFormView object.

After this has been set-up we can create the object.

Rending The Block

private static void RenderEpiserverContent(HtmlHelper html,
IContentData content,
string tag)
{
var templateResolver = ServiceLocator.Current.GetInstance();
var templateModel = templateResolver.Resolve(
html.ViewContext.HttpContext,
content.GetOriginalType(),
content,
TemplateTypeCategories.MvcPartial,
tag);

var contentRenderer = ServiceLocator.Current.GetInstance();
html.RenderContentData(
content,
true,
templateModel,
contentRenderer);
}

Now we have created our own HTMLHelper in code, we can get on with rendering the content.  In the code, I’m assuming you have got an IContent instance from IContentRepository.  In my code example, the way I got mine is very specific to my project and it’s based on getting the content reference from a third party source which won’t be relevant to anyone else, so I’m skipping that code.

The first part of getting this working is getting the correct template model for the content that we care about.  In order to do this, we use the Episerver TemplateResolver which we get from a ServiceLocator.

Using the HTML Helper we created, we pass in the page context.  We then pass the content data in.  In my situation, I only care about blocks and not pages, so I use the MvcPartial template type.  If you get this bit wrong then the template resolver will return null, so be warned you may need to experiment to get the object returned.

The last part is using the display tag, I’ve written about this before in How To Make A Block Use Multiple Views? A Partial View Controller Explained. More information about how to get the tag can be found here in How To Get The Action, Controller and Tag Data Out Of The Context In Episerver

Now we have all the configuration set-up.. eventually!  We can call the Episerver API.  To do that we create an instance of IContentRenderer from IContentRenderer from Service Locator, we pass in the content, if the items are in a content area, the new template model we created and the content render.

Getting The Block HTML Manually

We now have the data. If you remember the first step where we create a StringReader, our code should not look like this:

using (var textWriter = new StringWriter())
{
var htmlHelper = CreateHtmlHelper(filterContext.Controller, textWriter);
RenderEpiserverContent(htmlHelper, epiServerInstance, tag);
var blockHtml = textWriter.ToString();
}

To get the HTML all you need to do is call the ToString() method on the StringWriter and, voila,you have it.

Conclusion

In today’s tutorial, I’ve covered one method of getting block data from code.  Depending on where you are, say an attribute, a controller, or a standard bit of code.  The way you create the HTML helper way vary.  In a later guide, I’ll cover how to render a page controller in normal code when you don’t have access to the context.

The theory behind rendering the block content is quite simple. We create a new instance of HTMLHelper, create a stream writer, then call the Episerver extension to render the block passing in the correct template resolver.

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

More Posts

2 replies
  1. Adnan
    Adnan says:

    Hi, Great post, i am just wondering can you do all this based on ContentRefrence of Block by passing it to the static function?

    Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *