Using Html.Raw in ASP.NET MVC Razor Views

With the release of ASP.NET MVC 3 Release Candidate 2 (RC2) you can finally use Html.Raw when you don’t your output to be encoded.

So this means you don’t have to use

@MvcHtmlString.Create(ViewBag.HtmlOutput)

or

@(new HtmlString(ViewBag.HtmlOutput))

or anything else to output a string containing HTML in ASP.NET MVC.

An example of using Html.Raw in ASP.NET MVC 3 using Razor

The code below shows the HTML string to be outputted being added the dynamic ViewBag collection.

public class HomeController : Controller
{        
    public ActionResult Index()
    {
        StringBuilder htmlOutput = new StringBuilder();
        htmlOutput.Append("<p>The image below is from " );
        htmlOutput.Append("<a href=\"http://commons.wikimedia.org/wiki/Main_Page\">Wikimedia Commons</a>");
        htmlOutput.Append("</p>");
        htmlOutput.Append("<img src=\"http://upload.wikimedia.org/wikipedia/commons/6/63/CampNou.jpg\" alt=\"Cam Nou\" title=\"Cam Nou\"/>");
        ViewBag.HtmlOutput = htmlOutput.ToString();                
        return View();
    }
}

Which can be used in a view like this

@{
    ViewBag.Title = "Index";
}

@Html.Raw(ViewBag.HtmlOutput)

to show the following output in a browser

Output Using HtmlRaw in ASP.NET MVC

For more information check out Scott Gu’s post Announcing ASP.NET MVC 3 (Release Candidate 2).

When to use Html.RenderPartial and Html.RenderAction in ASP.NET MVC Razor Views

In this blog post I want to show examples when to use Html.RenderPartial and Html.RenderAction when creating web sites in ASP.NET MVC using the Razor view engine.

Some background information on Html.RenderAction and Html.RenderPartial

Html.RenderAction is a somewhat contentious feature because it invokes a controller action.

This means each time it’s called a new request (which has to go through the ASP.NET MVC pipeline) is made.

As shown below ASP.NET MVC requests are routed to a controller. It’s the controller that decides what view to call and what data (model) to pass to it.

Architecture for Html.RenderActionA view has one responsibility and that’s to render HTML. It’s supposed to be simple, it doesn’t know (or care) where the data in the model comes from.

The thing MVC traditionalists frown upon is the fact that Html.RenderAction can execute child actions in ASP.NET MVC views.

However given that Html.RenderAction just like an AJAX request is a form of sub request, the case against seems somewhat outdated and doesn’t take into the account using Html.RenderAction will allow you to separate concerns of models and controllers as we will see later in this post.

For Html.RenderPartial the content of the partial view is added to content of the host view, either directly to the response output (or by using a StringWriter if you use or Html.Partial).

Examples of when to use Html.RenderPartial and Html.RenderAction

The mockup below shows a blog post with comments and a list of categories in a side bar.

ASP.NET MVC mockup

When to use Html.RenderPartial (or Html.Partial)

For the page we’re designing I would create a view to show the blog post and call Html.RenderPartial to output the comments

@model WhenToUseRenderActionAndRenderPartial.Models.ShowPostViewModel
@{
    ViewBag.Title = Model.Post.Title;
}

<section>
    <article>
        <header>
            <h1>@Model.Post.Title</h1>        
        Posted on | <time datetime="@Model.Post.DatePublished.ToString("s")">
           @Model.Post.DatePublished.ToLongDateString() 
        </time> | @Model.Comments.Count() Comments
        </header>
        @Html.Raw(Model.Post.Content)
    </article>  
</section>
@{Html.RenderPartial("_Comments", Model.Comments);}

The partial view for comments would look like this

@model IEnumerable<WhenToUseRenderActionAndRenderPartial.Models.Comment>
<section>
    <header>
        <h3>
            Comments</h3>
    </header>
    @foreach (var comment in Model)
    {
        <article>
            <header>
                @comment.Author on 
                <time datetime="@comment.DateCreated.ToString("s") ">
                    @comment.DateCreated.ToLongDateString()
                </time>
            </header>
            <img alt="@comment.Author" src=@comment.ImageUrl />
            <p>
                @comment.Content
            </p>
        </article>
    }
</section>

This means the ShowPost action in the Blog controller

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using WhenToUseRenderActionAndRenderPartial.Models;

namespace WhenToUseRenderActionAndRenderPartial.Controllers
{
    public class BlogController : Controller
    {        
        public ActionResult ShowPost()
        {
            ShowPostViewModel viewModel = new ShowPostViewModel();
            viewModel.Post = new Post
                            {
                                Title = "Blog Title",
                                Content = "<p>Lorem ipsum dolor sit amet</p>",
                                DatePublished = new DateTime(2010, 10, 5)
                            };            
            viewModel.Comments = new List<Comment>()
                                             {
                                                 new Comment()
                                                     {
                                                         Author = "Andrew",
                                                         Content = "I think",
                                                         DateCreated = new DateTime(2010, 10, 5)
                                                     },
                                                new Comment()
                                                     {
                                                         Author = "Bill",
                                                         Content = "I reckon",
                                                         DateCreated = new DateTime(2010, 10, 5)
                                                     },
                                                new Comment()
                                                     {
                                                         Author = "Chris",
                                                         Content = "My opinion",
                                                         DateCreated = new DateTime(2010, 10, 6)
                                                     }
                                             };
            return View(viewModel);
        }
    }
}

needs to pass a model with properties for the blog post and its comments to the view.

public class Post
{
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime DatePublished { get; set; }
}

public class Comment
{
    public string Content { get; set; }
    public string Author { get; set; }        
    public string ImageUrl { get; set; }
    public DateTime DateCreated { get; set; }
}

public class ShowPostViewModel
{
    public Post Post { get; set; }
    public IEnumerable<Comment> Comments { get; set; }
}

When to use Html.RenderAction (or Html.Action)

So while we could add a property for categories to the ShowPostViewModel used for the ShowPost page and use Html.RenderPartial to display them, we have to add a category property to every model in our solution where categories are shown.

public class ShowPostViewModel
{
    public Post Post { get; set; }
    public IEnumerable<Comment> Comments { get; set; }
    public IEnumerable<Category> Categories { get; set; }
}

public class AnotherViewModel
{
    public string StringToOutput { get; set; }
    public IEnumerable<Category> Categories { get; set; }
}

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
}

And using a base class with a categories property and have ViewModel classes inherit from it would just be bloating models with unrelated data and concerns.

public class ViewModelBase
{        
    public IEnumerable<Category> Categories { get; set; }        
}

public class ShowPostViewModel : ViewModelBase
{
    public Post Post { get; set; }
    public IEnumerable<Comment> Comments { get; set; }
}

So if you want to display the same information on multiple pages and the data doesn’t necessarily depend on or isn’t related to the rest of the page, something like a widget to display categories then I would use Html.RenderAction.

As shown in the markup below Html.RenderAction is called from the layout page for the blog post.

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
</head>
<body>
    @RenderBody()
    @{Html.RenderAction("Show", "Category");}
</body>
</html>

Jag Reehal’s Final Thought on ‘When to use Html.RenderPartial and Html.RenderAction in ASP.NET MVC Razor Views’

In cases where a model for the page is already populated with all the information required I would use Html.RenderPartial.

If the same information is shown on multiple pages it’s likely that the data needs to be in its own model so I would use Html.RenderAction. As shown in this post I would say layout pages are going to the most common place Html.RenderAction will be used.

ASP.NET MVC Razor View Best Practices – Keep logic out of your Razor views

Last year I wrote a blog post about how you could keep logic out of your ASP.NET MVC views.

Now with the introduction of the Razor view engine for ASP.NET MVC, I thought it would be a good idea to do a ‘Razor’ version.

The code used in this post can be downloaded here.

If you recall the reasons you should not have logic in your views are because they will become difficult to read, maintain and test at the very least.

How to decide what CSS class to use for the stock level in a Razor view

The screenshot below shows the three possible messages displayed to the user depending on the number of units in stock.

Output For Logic Out Of Views Blog Post

An example of a Razor view with conditional logic

We could select the CSS class for the corresponding number of units in stock using multiple if statements like this

@inherits System.Web.Mvc.WebViewPage<KeepLogicOutOfYourRazorViews.Models.Product>
@using KeepLogicOutOfYourRazorViews.Helpers

@{
	View.Title = "Index";
	LayoutPage = "~/Views/Shared/_Layout.cshtml";
}

<div class="example">
@if(Model.UnitsInStock == 0){	
								<div class="stockLevel stockLevelNone">
									<span>Number Of Units In Stock: @Model.UnitsInStock</span>
								</div>
							}
@if(Model.UnitsInStock > 0 && Model.UnitsInStock <= 20)	
							{ 
								<div class="stockLevel stockLevelLow">
									<span>Number Of Units In Stock:	@Model.UnitsInStock</span>
								</div> 
							}
@if(Model.UnitsInStock > 20){	
								<div class="stockLevel stockLevelHigh">
									<span>Number Of Units In Stock: @Model.UnitsInStock</span>
								</div> 
							}		 		
</div>

but there are better ways to achieve our goal.

So what are the alternatives?

We could:

  • Move the logic for choosing the CSS class into a helper method
  • Create a method to build the HTML for displaying the number of units in stock
  • Use a Product data transfer object with a CSS class name property
  • Pass all the CSS classes to a method which will return the CSS class to use

As I want to concentrate on showing code for Razor view engine, if you want to see the methods, unit tests and discussion about the advantages and disadvantages of each option please refer to the original post.

What the view would look like if we used a method to get the CSS class in a Razor view

The code below shows how we could achieve the same result by calling a method which returns the CSS class for the number of units in stock.

@inherits System.Web.Mvc.WebViewPage<KeepLogicOutOfYourRazorViews.Models.Product>
@using KeepLogicOutOfYourRazorViews.Helpers

@{
	View.Title = "Index";
	LayoutPage = "~/Views/Shared/_Layout.cshtml";
}

<div class="example">
	<div class="stockLevel @ProductCssHelper.GetCssClassForUnitsInStock(Model.UnitsInStock)">
		<span>Number Of Units In Stock: @Model.UnitsInStock</span>
	</div> 			 		
</div>	

What the view would look like if we passed the CSS classes to a method in a Razor view

Alternatively, a more designer friendly way would be to pass the CSS classes to a method which returns the appropriate CSS class to use for the stock level.

@inherits System.Web.Mvc.WebViewPage<KeepLogicOutOfYourRazorViews.Models.Product>
@using KeepLogicOutOfYourRazorViews.Helpers

@{
	View.Title = "Index";
	LayoutPage = "~/Views/Shared/_Layout.cshtml";
}

<div class="example">
	<div class="stockLevel 
		@ProductCssHelper.SelectCssClassForUnitsInStock(
														 Model.UnitsInStock,
														 "stockLevelNone",
														 "stockLevelLow",
														 "stockLevelHigh"
													   )">
		<span>Number Of Units In Stock: @Model.UnitsInStock</span>
	</div> 			 							
</div>		 											 										 		

Jag Reehal’s Final Thought on ‘ASP.NET MVC Razor View Best Practices – Keep logic out of your Razor views’

Razor does a fantastic job of cleaning up your views, but to keep them even cleaner the best practice to keep logic out of yours view still applies.

Page 3 of 512345