How To Make A Block Use Multiple Views ? A Partial View Controller Explained

One of the main benefits of using MVC is the separation between the view and the model.  This separation means a block or page can have more than one view.  In Episerver we have several methods available to us for rendering views.  In today’s article I’m going to go discuss rendering content without a controller.

When you render content within MVC that only needs a view and/or model and doesn’t need the overhead of a controller, you can use something called a partial view.   When I first heard about partial views I struggled to get my head around the concept of how they worked in Episerver.

If you are currently in the same boat as I was, here is a list of benefits:

  • When you have a very lightweight block like a text block, a banner, promo, image block or call to action that needs no logic to be added within view model or a controller, why waste the extra overhead creating a controller when you can simply let MVC use a default controller that will figure out which view to use.
  • Using a partial view has performance benefits as well.  When returning the view, a partial only requires a call to RenderPartial instead of RenderAction which saves a few processing cycles.

Partial Views

A partial view is a pretty easy concept to get your head around.  It’s a rendering (think page or block) that is displayed without a controller.  To display a partial from a view you would use the following snippet:

@Html.Partial("BlockView", Model.Block)

In Episerver we work with dynamic content, so it’s not always as easy to define at compile time what views are needed.  This is why we need something behind the scenes that will hook up pages or blocks to the correct view for us.  When you render a block in a view it will more than likely be coming from a ContentArea using the PropertyFor helper, like so:

@Html.PropertyFor(x => Model.PromoBlock, new
{
Tag = "PromoNormal"
})

If this PromoBlock has an associated controller, the Index Action will be called in that controller and usually a view model will be created and the correct view will be called.  If our block doesn’t have an associated controller, an error will be displayed that the MVC pipeline couldn’t find an appropriate view for it.

This means when we work with partials you will need to create a handler for partial requests.  This handler will intercept controller-less requests and point the pipeline in the right direction.

Your partial views will usually live in your ‘Shared’ folder in your web projects ‘View’ folder.  You may want to create two Sub Folders called Pages and Blocks and separate out your files to make your life easier, but that’s entirely optional.

Display Options

EPiServer also throws another curve ball into the partial mix as editors can also set how blocks are displayed using display options.  In Episerver you can define DisplayOptions for partials.  If this feature is enabled, a content editor will have access to a menu in episerver that will allow them to set the rendering style of the partial, this can be customised but the out of the box options are Full Width, Two Thirds, Half Width, One Third and One Fourth.

episerver_display_options_dialog

After enabling this feature in your project, when a content editor selects the rendering size, a tag is also generated and added to the pipeline as well as the partial request

Partial View Controller

How does Episerver display a partial if it has no controller?  There are a few ways we can deal with partials, the first one being a partial controller.  The first thing we do is create a base partial controller.  This allows us to target individual types, if we want to, which can be really useful.

[TemplateDescriptor(TemplateTypeCategory = TemplateTypeCategories.MvcPartialController, Inherited = true,
AvailableWithoutTag = false)]
public class BasePartialController<T> : PartialContentController<T> where T : IContentData
{
public BasePartialController()
{
}
}

To create a base controller you need to register it with the TemplateModelRepository, as shown below.  A partial controller needs to inherit from  PartialContentController rather than the more standard PageController for normal pages.  The other important thing to remember when using a partial controller in Episerver, is to decorate your controller with the Template Descriptor attribute.

Next up we will create a default partial controller that will deal with all blocks:

public class BlockPartialController : BasePartialController<BlockData>
{
private const string PARTIAL_VIEW_DIRECTORY = "~/Views/Shared/Blocks/";
public override ActionResult Index(BlockData blockData)
{
var viewName = string.Empty;
if (blockData == typeof(PromoBlock))
{
viewName = "promo";
}
return PartialView(string.Format("{0}{1}.cshtml", PARTIAL_VIEW_DIRECTORY, viewName ));
}
}

Our code inherits from our base controller and will capture all incoming partial requests for any blocks. In the index method we can either direct all requests to the same view, which is kinda pointless, or, we can check the type of the block and forward it on to it’s associated partial.

Template Co-ordinator

So we’ve talked about how to define partials with a controller, next we’ll talk about how to deal with partials using a template co-ordinator.

The template coordinator is slightly different than a controller;  the template coordinator registers all your partial requests on application start.  The coordinator in a single location to define all of your partial mapping definitions.  To create a template coordinator, you need to declare it with a ServiceConfiguration attribute of type IViewTemplateModelRegistrator.

[ServiceConfiguration(typeof(IViewTemplateModelRegistrator))]
public class TemplateCoordinator : IViewTemplateModelRegistrator
{
public const string BlockFolder = "~/Views/Shared/Blocks/";
public const string PagePartialsFolder = "~/Views/Shared/PagePartials/";
public static void OnTemplateResolved(object sender, TemplateResolverEventArgs args)
{
}
public void Register(TemplateModelCollection viewTemplateModelRegistrator)
{
viewTemplateModelRegistrator.Add(typeof (PromoBlock), new TemplateModel()
{
Name = "Promo",
Tags = new[] { ContentAreaTags.FullWidth },
AvailableWithoutTag = false,
Path = Path = BlockPath("GamePromoNormal.cshtml")
});
}
public static string BlockPath(string fileName)
{
return string.Format("{0}{1}", BlockFolder, fileName);
}
public static string PagePartialPath(string fileName)
{
return string.Format("{0}{1}", PagePartialsFolder, fileName);
}
}
public static class ContentAreaTags
{
public const string FullWidth = "FullWidth";
public const string TwoThirdsWidth = "TwoThirdsWidth";
public const string HalfWidth = "HalfWidth";
public const string OneThirdWidth = "OneThirdWidth";
public const string OneFourthWidth = "OneFourthWidth";
}

This code is very similar to the controller code, we override

void Register(TemplateModelCollection viewTemplateModelRegistrator);

In the register method, you can then define the mapping between the block being requested and the view the coordinator should send, like we did for our controller.  In the sample code below, you can see how we add our definitions into the viewTemplateModelRegistrator.  One thing you might notice from the code and that we’ve also yet to cover, is the Tags property.

The Tags property relates to the Episerver display options as discussed above.  For our Promo Block we may end up with 5 different views called:

  • PromoBlockFull
  • PromoBlockHalf
  • PromoBlockNarrow
  • PromoBlockQuarter
  • PromoBlockWide

Using the tags parameter allows us to swap between these different display options.  You can set one rule for a Full and a different rule for Half, or even a mix and match approach.

Why use Partials At All?

So you might be asking what’s the benefit of this so far?  You could have just created a controller for the Promo Block, why bother creating a separate controller just to deal with one block ?  The answers simple.  From Episerver 7 onwards as well as rendering a page normally, editors can also drag blocks and pages into content areas.  Having a partial controller for a page allows us, as developers, to create different views and gives us more flexibility.  This means you can have a page that has a lot of logic and dependencies in it (say a product page() for full page rendering and a simple partial view for something like a drag and drop product spot light area.

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

11 replies
  1. Andy
    Andy says:

    Nice post. I have similar requirement but in web forms. Where the controller and the template coordinator code should be placed in web forms?

    Reply
  2. Gary Hodge
    Gary Hodge says:

    Hi Jon, its gary

    This is a good entry….Ive been trying to tackle a similar issue.

    I have a model “Detail” which lots of properties…its a BlockData type
    I have “n” view models which I want to map certain properties from “Detail” – I may have summary, CTA, any number of smaller models that map from detail and project certain properties.
    I also have a a view for each view model.

    I want to have a number of instances of “Detail” in Episerver, but at the time I drop into a ContentArea, I want to specify the viewmodel or view that will render it….

    …if you see what I mean.

    I donnt want to clutter blockdata with multiple types of the same content (eg my clients will only want to edit an “Event” item in the CMS, but be able to select which components render it depending on which page they are editing

    Reply
    • Jon D Jones
      Jon D Jones says:

      Alright mate, uhmm I think I get you, some options off the top of my head:

      1. Partial Router. You can set tag on top of a controller so when a block is added to a content editor with a certain view, when the pipeline load it will automatically call that controller.
      2. Can you not put some type of display option property on yo9ur block type definition and then have some logic in the controller to determine the view baed on the property?

      Reply

Trackbacks & Pingbacks

  1. […] In Episerver, blocks and block partials are rendered using the template resolver.  The template resolver can be overridden and if you want to render your blocks with display options or without a controller, then this is something that you may look into (How To Make A Block Use Multiple Views? A Partial View Controller Explained). […]

  2. […] 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 […]

  3. […] Another property that I’ve talked about previous in : How To Make A Block Use Multiple Views ? A Partial View Controller Explained […]

  4. […] out all variations of the block based on these display options. I’ve talked previously about display options and I’m assuming you have all that bit set-up. If you go to the end of this tutorial you can […]

  5. […] talked previously in How To Make A Block Use Multiple Views ? A Partial View Controller Explained about what developers need to do in order to render partial views in EpiServer. EpiServer uses the […]

  6. […] with EpiServer we have page types and blocks. I’ve talked previously about how to set-up a How To Make A Block Use Multiple Views ? A Partial View Controller Explained Today I’ll talk you through how to display a page type as a […]

  7. […] Store EPiServer Blocks A Quick Reference Guide Sitecore 7 : Getting Started The Basics How To Make A Block Use Multiple Views ? A Partial View Controller Explained 0 […]

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 *