How To Manually Render A Episerver Page Or Block Using .NET

This post is another code example that the majority of people will never really need. If you are reading this and you think you want to use the demo code, then my advice would be to strongly consider if the design of your project is correct. In almost every situation, it’s a lot easier to let Episerver and the Episerver API do the hard work for you rather than do it manually. If you are interested in roughly how Episerver hi-jacks the MVC pipeline and renders virtual pages then the code is definitely worth giving a once over.

How To Manually Render Episerver Code

In order to manually render a page or a block, the first thing you will need to do is manually generate the data that Episerver would normally pass into the controller and a few other little gems, which include the Episerver page, a view model (I assume you use them!), the controller to use, the action to invoke and the site’s Url.

In my example below, I’m manually rendering’Content Pages’ which is a custom page type that I’ve defined myself.

The Page Type

The content page type definition class, looks like this:

[ContentType(
DisplayName = "Content Page",
GUID = "8dee011f-8dbf-43ab-b4f3-211db5ceb9d5",
Description = "Content Page",
GroupName = "Standard")]
public class ContentPage : GlobalBasePage
{
[Display(
Name = "Page Title",
Description = "Page Title",
GroupName = SystemTabNames.Content,
Order = 100)]
[CultureSpecific]
public virtual string PageTitle { get; set; }
[Display(
Name = "Main Content Area",
Description = "Region where content blocks can be placed",
GroupName = SystemTabNames.Content,
Order = 200)]
public virtual ContentArea MainContentArea { get; set; }
}

The View Model

The view model class, looks like this:

public class ContentPageViewModel : PageViewModel<ContentPage>
{
private readonly ContentPage _currentPage;
public ContentPageViewModel(ContentPage currentPage)
{
}
}

The Controller

The page controller class, looks like this:

public class ContentPageController : PageController<ContentPage>
{
public ActionResult Index(ContentPage currentPage)
{
return View("Index", new ContentPageViewModel(currentPage));
}
}

The Code

So, now we have the basics defined for the content page, we will need the following bits of data in order to manually render it:

  • An Instance Of a Page
  • The View Model
  • The Name Of The Content Pages Controller
  • The Action Within The Controller To Invoke

NOTE: I wrote the code below in a way to make it easy to understand. In a production environment, I would make this code a lot more generic, but I’ll leave that for you 🙂

Getting The View Model

Creating the view model is pretty easy. In my example, I’m using the Episerver API and a page ID to create an instance of a page

var repository = ServiceLocator.Current.GetInstance<IContentRepository>();
var contentReference = new ContentReference(pageId);
var contentPage = repository.Get<ContentPage>(contentReference);
return new ContentPageViewModel(contentPage);

Getting The Controller Name

Hard coding names are bad, so instead we can use reflection on the content page controller to get its name

var controllerName = controller.GetType().Name;
var index = controllerName.IndexOf("Controller");
return index < 0
? controllerName
: controllerName.Remove(index, "Controller".Length);

The Index Name

This part is easy, I just hard code in the ‘Index’ string:

routeData.Values.Add("Action", "Index");

The Request Url

This is just the Site’s Url, which we can get from the EPiServer.Configuration.Settings.Instance, like so:

var siteUrl = EPiServer.Configuration.Settings.Instance.SiteUrl.ToString();

Now we have all the pieces of the puzzle, we can now write some code to actually manually render the HTML we want:

var controllerContext = new ControllerContext
{
RouteData = routeData,
Controller = controller,
HttpContext = new HttpContextWrapper(httpContext)
};
var viewResult = ViewEngines.Engines.FindPartialView(controllerContext,
"~/Views/Pages/ContentPage/index.cshtml");
using (var stringWriter = new StringWriter())
{
var viewContext = new ViewContext(controllerContext,
viewResult.View,
viewDataDictionary,
new TempDataDictionary(),
stringWriter);
viewResult.View.Render(viewContext, stringWriter);
return stringWriter.ToString();

First, we create a new controller context. When we work with MVC the controller context is the basic building block for any MVC controller. In here we define the route data (controller name, action and view model), an instance of the controller we want to call and a new HttpContext instance.

We set the view we want to call, by calling GetPArtial(). Then we create a new View Context and call the view render method to manually call it. As part of the view context, we pass in a string builder. In this string builder, all the rendered HTML of the controller will be rendered.

The Final Code

using EPiServer;
using EPiServer.Core;
using EPiServer.ServiceLocation;
using JonDJones.Com.Controllers.Pages;
using JonDJones.Com.Core;
using JonDJones.Com.Core.Pages;
using JonDJones.Com.Core.ViewModel.Pages;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace JonDJones.com.Core
{
public static class RenderControllerManually
{
public static string Render(int pageId, IEpiserverDependencies epiServerDependencies)
{
var viewModel = CreatePageTypesViewModel(pageId, epiServerDependencies);
var viewDataDictionary = new ViewDataDictionary(viewModel);
var controller = new ContentPageController();
var controllerName = GetControllerName(controller);
var routeData = new RouteData();
routeData.Values.Add("Action", "Index");
routeData.Values.Add("controller", controllerName);
var siteUrl = EPiServer.Configuration.Settings.Instance.SiteUrl.ToString();
var httpContext = new HttpContext(
new HttpRequest(string.Empty, siteUrl, string.Empty),
new HttpResponse(TextWriter.Null));
var controllerContext = new ControllerContext
{
RouteData = routeData,
Controller = controller,
HttpContext = new HttpContextWrapper(httpContext)
};
var viewResult = ViewEngines.Engines.FindPartialView(controllerContext,
"~/Views/Pages/ContentPage/index.cshtml");
using (var stringWriter = new StringWriter())
{
var viewContext = new ViewContext(controllerContext,
viewResult.View,
viewDataDictionary,
new TempDataDictionary(),
stringWriter);
viewResult.View.Render(viewContext, stringWriter);
return stringWriter.ToString();
}
}
private static string GetControllerName(ContentPageController controller)
{
var controllerName = controller.GetType().Name;
var index = controllerName.IndexOf("Controller");
return index < 0
? controllerName
: controllerName.Remove(index, "Controller".Length);
}
private static ContentPageViewModel CreatePageTypesViewModel(int pageId, IEpiserverDependencies epiServerDependencies)
{
var repository = ServiceLocator.Current.GetInstance<IContentRepository>();
var contentReference = new ContentReference(pageId);
var contentPage = repository.Get<ContentPage>(contentReference);
return new ContentPageViewModel(contentPage, epiServerDependencies);
}
}
}

You can then call the code directly like this:

var content = RenderControllerManually.Render(48, EpiserverDependencies);

Conclusion

Today’s post was slightly different than normal. In this post, I’ve hopefully demonstrated how to manually render an Episerver page or block via normal MVC.

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

1 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 *