Defining Default Content For A Razor Layout Section

Layouts in Razor serve the same purpose as Master Pages do in Web Forms. They allow you to specify a layout for your site and carve out some placeholder sections for your views to implement.

For example, here’s a simple layout with a main body section and a footer section.

<!DOCTYPE html>
<html>
<head><title>Sample Layout</head>
<body>
    <div>@RenderBody()</div>
    <footer>@RenderSection("Footer")</footer>
</body>
</html>

In order to use this layout, your view might look like.

@{
    Layout = "MyLayout.cshtml";
}
<h1>Main Content!</h1>
@section Footer {
    This is the footer.
}

Notice we use the @section syntax to specify the contents for the defined Footer section.

But what if we have other views that don’t specify content for the Footer section? They’ll throw an exception stating that the “Footer” section wasn’t defined.

To make a section optional, we need to call an overload of RenderSection and specify false for the required parameter.

<!DOCTYPE html>
<html>
<head><title>Sample Layout</head>
<body>
    <div>@RenderBody()</div>
    <footer>@RenderSection("Footer", false)</footer>
</body>
</html>

But wouldn’t it be nicer if we could define some default content in the case that the section isn’t defined in the view?

Well here’s one way. It’s a bit ugly, but it works.

<footer>
  @if (IsSectionDefined("Footer")) {
      RenderSection("Footer");
  }
  else { 
      <span>This is the default yo!</span>   
  }
</footer>

That’s some ugly code. If only there were a way to write a version of RenderSection that could accept some Razor markup as a parameter to the method.

Templated Razor Delegates to the rescue! See, I told you these things would come in handy.

We can write an extension method on WebPageBase that encapsulates this bit of ugly boilerplate code. Here’s the implementation.

public static class Helpers {
  public static HelperResult RenderSection(this WebPageBase webPage, 
      string name, Func<dynamic, HelperResult> defaultContents) {
    if (webPage.IsSectionDefined(name)) {
      return webPage.RenderSection(name);
    }
    return defaultContents(null);
  }
}

What’s more interesting than this code is how we can use it now. My Layout now can do the following to define the Footer section:

<footer>
  @this.RenderSection("Footer", @<span>This is the default!</span>)
</footer>

That’s much cleaner! But we can do even better. Notice how there’s that ugly this keyword? That’s necessary because when you write an extension method on the current class, you have to call it using the this kewyord.

Remember when I wrote about how to change the base type of a Razor view? Here’s a case where that really comes in handy.

What we can do is write our own custom base page type (such as the CustomWebViewPage class I used in that blog post) and add the RenderSection method above as an instance method on that class. I’ll leave this as an exercise for the reader.

The end result will let you do the following:

<footer>
  @RenderSection("Footer", @<span>This is the default!</span>)
</footer>

Pretty slick!

You might be wondering why we didn’t just include this feature in Razor. My guess is that we wanted to but just ran out of time. Hopefully this will make it in the next version of Razor.

What others have said

Requesting Gravatar... Marcin Dobosz Mar 05, 2011 9:35 AM
# re: Defining Default Content For A Razor Layout Section
Looks like something I've seen before (Optional Razor Sections with Default Content) :) Also check out Razor, Nested Layouts and Redefined Sections for even more advanced scenarios.
Requesting Gravatar... haacked Mar 05, 2011 9:58 AM
# re: Defining Default Content For A Razor Layout Section
@Marcin Ha! Great minds think alike. I should make sure to subscribe to your blog. :)
Requesting Gravatar... Andrew Wrigley Mar 05, 2011 5:26 PM
# re: Defining Default Content For A Razor Layout Section
Looks like this should be part of MVC 4.
Requesting Gravatar... Ben Mar 05, 2011 7:12 PM
# re: Defining Default Content For A Razor Layout Section
I was wondering today what a good way of rendering footers would be. Thanks for reading my mind and coming up with this post :)
Requesting Gravatar... ViewStartLover Mar 05, 2011 8:12 PM
# re: Defining Default Content For A Razor Layout Section
Why wasn't this solved using the ViewStart files? They already contain common functionality. If ViewStart files could just define template sections, none if this black magic would be required.

C.f. http://www.dotnetcurry.com/ShowArticle.aspx?ID=605
Requesting Gravatar... Lukas Kubis Mar 12, 2011 1:11 AM
# re: Defining Default Content For A Razor Layout Section
@ViewStartLower: I think that you can use declarative html helpers inside App_Code folder for all views. Look at my post blog.lukaskubis.net/...
Requesting Gravatar... Rush Mar 17, 2011 10:50 PM
# re: Defining Default Content For A Razor Layout Section
The original way is way better. Why does everyone want to make their code "pretty" by getting it down to one line? It won't be pretty if you have a lot of default content to stuff in there.
Requesting Gravatar... Petr Divis Apr 22, 2011 7:24 AM
# re: Defining Default Content For A Razor Layout Section
what another PHP framework (Nette) does with sections (here blocks) is inheritance:
1. you declare default content in the layout file by typing:

{block #title}I'm the default content!{/block}

2. the view file optionally overwrites the section or even includes it:
{block #title}Child content with parent content: {include #parent}{/block}

--awesome, you should think about it for MVC4

Nette has also pretty good ajax snippets, caching options and other stuff, but since I'm beginning to learn MVC3, I don't know how it works exactly.

But Phill, you should check it out and please, add some modularity for enterprise webapps to be developed easily, because right now I have to deep dive into all the DI frameworks to get to know them and decide how to inject modules with controllers and views for my diploma thesis project (how it's done in Orchard), but there are no tutorials:(

Requesting Gravatar... Fabian Aug 09, 2011 8:42 PM
# re: Defining Default Content For A Razor Layout Section
You could add this signature to the help in the case you want to use Html.Partial() has the default content:

public static HelperResult RenderSection(this WebPageBase webPage, string name, IHtmlString defaultContents)
{
if (webPage.IsSectionDefined(name))
{
return webPage.RenderSection(name);
}

var result = new HelperResult((x) => x.Write(defaultContents.ToString()));

return webPage.RenderSection(name, (x) => result);
}
Requesting Gravatar... Jack Sep 03, 2011 7:48 PM
# re: Defining Default Content For A Razor Layout Section
MVC3 / Razor is a total mess. The team behind it are out-of-control amateurs and should be sacked. Time for ANOTHER vote of no-confidence from the community. Microsoft are wasting our time and energy. Wise up people.
Requesting Gravatar... andrew boudreau Sep 23, 2011 12:10 AM
# re: Defining Default Content For A Razor Layout Section
It's important to note that if you do change the BasePageType and create a custom implementation of WebViewPage then you need to extend the generic and non-generic classes separately. I had a pretty tricky time figuring out why my some of my expressions weren't able to do type-inference on the typed view<viewmodel>. After adding RenderSection methods to both CustomWebViewPage and CustomWebViewPage<TModel> i was back in business, great article.
Requesting Gravatar... kaicui Feb 13, 2012 2:26 AM
# re: Defining Default Content For A Razor Layout Section
hi,i'm a chinese programmer and i have got a problem in my work.I have spend a lot of time but can't find the answer.(my english is pool so i will try to explain it clearly^_^).

The problem is this:
1、in MVC3.0,Razor viewEngine,i want to put every <Script> block to the bottom of page(usually before "</body>" tag).
2、So i use a "RenderSection" in the layout page and put it in the bottom of page,other page( who use the page as their layout page) define their script Section,these section contains javascript the page needs.
3、question come out:if my page has some paticalPage,in partial page,i can't define scriptblock because the layout page cannot render it

PS:because i have to pass some server para to the script so i can't write script in one page,so i need a method to put any script whitch writing in any pages can be moved to the </body> Tag
Requesting Gravatar... Notre Feb 22, 2012 9:23 PM
# re: Defining Default Content For A Razor Layout Section
@haicui I couldn't quite understand your problem, so I'm not sure if this will help. But take a look at:

weblogs.asp.net/...

What do you have to say?

(will show your gravatar)
Please add 8 and 3 and type the answer here: