14 Days Free Technical Video Training from WintellectNOW

  

Partial views in ASP.NET MVC 3 w/the Razor view engine

Tags: ASP.NET, ASP.NET MVC, Razor, Visual Studio 2010

What is a partial view and when should I use it?

As developers become familiar with the ASP.NET MVC model, they'll naturally want to create reusable components filled with content & code. In Web Forms, we could do this by creating a web user control or a web server control, but in MVC, we will use partial views. You'll notice that conceptually, all of the scenarios below would work for either technology.

  • A stock ticker that's displayed on each page in an application.
  • A calendar widget that's displayed on multiple pages in application.
  • A login box.
  • A social networking component used on multiple pages, such as a Facebook Like button.

While ASP.NET MVC partial views may behave similarly in theory to web user controls, syntactically and functionally, the two behave differently. Web user controls found in web forms uses ViewState, PostBacks, and Events while MVC partial views do not use any of the preceding techniques for managing state. Just as ASP.NET web user controls do, partial views can tap into the models contained in your application as well as share data between other application components.

Rendering partial views

Partial views in ASP.NET MVC 3 allow the developer to create reusable content with the very precise and clean Razor syntax (or ASPX). The syntax that renders the partial view is implemented as an Html helper. The Html.Partial helper renders the partial view named "_FeaturedProduct" inline. The first argument of all overloaded methods in the call the @Html.Partial expect the view/partial's file name, without the file extension. Adhering to convention, the @Html.Partial helper assumes the view resides in the \Views\Shared\ folder. Additional overloads in the @Html.Partial method allow you to pass ViewData/ViewBag objects between views/partials (see below under Sharing data...).

The code below demonstrates the call to render the featured product partial view.

<div>
  @Html.Partial("_FeaturedProduct")
</div
>

Partial views can be rendered inside a Layout Page (or if using MVC 2/3 w/ASPX, the Master Page) as well as regular views.

There are some cases where you might like to step aside and write directly to the HTTP Response stream rather than having a partial view render the results (partials/views use MvcHtmlString/StringWriter). To do so, use the Html.RenderPartial helper.

<div>
  @Html.RenderPartial("_FeaturedProduct")
</div
>

Use Html.RenderPartial for streaming images or other elements that are media-centric or where faster download times are highly important.

Creating a partial view

Both partial views and regular views are .cshtml files, with the difference being the folder where the partial views reside: \Views\Shared\. Use the Add New View dialog by accessing the context menu from the \Views\Shared node in Solution Explorer. The Add New View template dialog offers choices for creating your partial views, including the option for strongly typing views. Don't forget to check off  "Create as a partial view" or you'll end up with a lot of code to delete.

SNAGHTML44dfac8

Once you've created the view you can get started customizing it by simply editing the file. There's no problem in deleting or modifying the view's code, as there's no designer tied to it. The code shown below (_FeaturedProduct.cshtml) is the same code the default view template creates, but modified to display the featured product differently:

<style type="text/css">
    .featuredProduct {border: solid 1px #000}
</style
>
<
div>
    <div>
        <h2>
            Our Featured product:<br />
            @ViewBag.FeaturedProduct.Name
        </h2>
    </div>    <div>
        <h3>
            Now discounted to $@String.Format("{0:F}", ((decimal)ViewBag.FeaturedProduct.Price)-100)
        </h3>
    </div>  
    <div>
        @Html.ActionLink("Featured Product Details", "Details", new { id = ViewBag.FeaturedProduct.ProductId })
    </div> 
    <div>
        <img class="featuredProduct" src="@Href("~/Content/Images")/@ViewBag.FeaturedProduct.ImageName" alt="Featured Product"/>
    </div
>
</
div
>

As with strongly typed views, strongly typed partial views also support dot notation syntax and access to the model, ViewBag, ViewData and other classes specifically designed for sharing data.

It should be clear when reading through the above code that the syntax of partial view looks the same as a regular view. The important take-away is not about the syntax but how the partial view is used. However, a syntactic benefit to developers is the consistency between both partial and full views, particularly when we need to share data between them.

Sharing Data between views and partial views

It's a common occurrence to pass data between components of an application, and in this case those components are MVC partials, views & controllers. As previously noted, you should use the ViewBag or ViewData classes to share data across views and controllers. First, a few notes on ViewBag and ViewData:

  • ViewData was available in previous versions; ViewBag was released with MVC 3.
  • ViewData can contain any type of data in a name-value pair format. I.e., ViewData["Message"] = "Welcome";
  • ViewBag objects are just wrappers around ViewData objects, and allow developers to code to them using strongly typed syntax.
  • ViewBag objects can be extended by simply setting properties in a more fluent syntax. I.e.,  ViewBag.Customer = new Customer(1,"Smith");

If code in a controller uses either the ViewBag or ViewData classes, those classes will be available throughout the view's lifecycle, and that includes its partial views. 

The preferable object is the ViewBag. Because of its more fluent and dynamic syntax, there's more complex objects that can be shared quite easily between components. The sample below demonstrates setting up the ViewBag object in the controller so it will be available to all necessary components:

ProductModel productModel = new ProductModel();        
public ActionResult Index()
{
    ViewBag.FeaturedProduct = new FeaturedProduct(105, "The Most Awesome Bike Ever!", 1000.00M, "bike4.png");          
    return View(productModel.Products);           
}

The ViewBag is accessed inside the view or partial using the follows syntax:

@ViewBag.FeaturedProduct.Name

Summary

Partial views are a great way to reuse fragments of HTML and Razor syntax together, with the ability to easily share data.

Resources:

Introducing Razor

Introducing MVC Development w/the Razor View Engine

Razor View Syntax

55 Comments

  • Nathan Bellamore said

    I am writing to ask how you would include images / css for the partials. i.e. I'd like to be able to create Partial Views - that I can supply to third parties to include in there solution. Would you create a folder under Views/Shared/Java Views/Shared/css Views/Shared/Images etc etc - then you can just package up a folder containing Partial Views.

    Also - the Controller passes through objects require by the Partial. How would you map a site which had a required parameter called X, but we wanted Parameter Y injected.

  • William said

    I also recently discovered the helper methods which are great, for example, my users insist that all forms have buttons on the top and on the bottom, this means that I need to duplicate html on both ends, but with @helper methods, this becomes really easy:

    @helper Buttons(string OkText, string CancelText) {
    <input type=submit value='@OkText' />
    <input type=button value='@CancelText' />
    }

    and on the html you just type:

    @Buttons("Save this Record","Cancel and Return")

  • Keith Petersen said

    The RenderPartial code snippet in your post won't display anything because of the @ in front of Html.RenderPartial. This is because the @ in this case stands for Response.Write to write a string, and RenderPartial sends it directly to Response.Output rather than creating a string.

  • Mazlan said

    Sorry, not really helpful, you not telling how the partial view is used. Beginner for MVC partial view still dont have a picture of it as this post have a good Google rank.

  • Rachel said

    @Keith

    The @ character is the marker to denote that Razor code is to follow (with an intelligent parser that can tell @ when it's code or an email, etc..)

    If you review the post, you'll see I said "There are some cases where you might like to step aside and write directly to the HTTP Response stream rather than having a partial view render the results", meaning that yes, it does go directly to the response stream. (I just didn't use the words Response.Write/Output)

  • Rachel said

    @Mazlan

    I'll be writing more on partial views in the future. This isn't necessarily a "total beginners" post however I do mention in the first paragraph many use cases for partial views.

  • Rachel said

    @jigar,

    Yes. If you look at MvcScaffolding created by the ASP.NET team, you'll see they do exactly what you're looking for.

    See here: http://rachelappel.com/build-data-driven-sites-using-the-mvc-3-tools-update-with-mvcscaffolding

    and here: http://rachelappel.com/ready-set-scaffold-build-asp.net-mvc-3-applications-quickly-with-mvcscaffolding

    Those posts have the info you're looking for.

  • darsys said

    Found this post very straight forward. I am relatively new to mvc3 and needed a basic overview. I searched all over and this is the most usefull article I found so far. Thanks for taking the time to help me out.

  • Joshua said

    I think what some people are saying is that if you use a partialview for Edit aka HTTPPOST whatever is entered into the partialview comes back as null

  • Rachel said

    Joshua,

    If that happens folks need to check to make sure the model class's property names math exactly the same id attribs rendered in the browers, or MVC can't bind those properties, and they'll be null.

  • Ramon Araujo said

    Hi Rachel,

    Awesome article! Please change the text:
    " the @Html.Partial helper assumes the view resides in the \Shared\Views\ folder"
    to:
    " the @Html.Partial helper assumes the view resides in the \Views\Shared\ folder"

  • Rais Hussain said

    Hi Rachel,

    Nice article, one thing I want to ask you, is it necessary to name a partial view starts with underscore like _FeaturedProducts?
    You used _underscore with FeaturedProducts or is it a way to distinguish partial views to web page views?
    Thanks

  • Rachel said

    Rais,

    Yes, the underscore is used to distinguish a partial view from a regular view. If you try to browse the partial view directly, you'll get an error (the same one you get when you try to browse global.asax).

    Mechanically, you can still call any view with Html.Partial, regardless of whether or not the underscore is present. However, it's best to name partials with underscores for clarity.

  • Jack said

    Layouts, Sections, Helpers, Views, Partial Views ... are all essentially the SAME THING - a method call defined with cshtml.
    Why don't you just provide support for METHODS in CSHTML files and then we can do all this for ourselves.
    This architecture is ridiculous.

  • Rachel said

    Jack,

    Methods are units of work that generally return a value, though that's not mandatory. Methods are a feature of languages.

    ASP.NET MVC is a technology, not a language. It's the MS implementation of the MVC pattern.

    There is support for methods, as you can use C#/VB language to write them in .cs/.vb files or right within Razor .cshtml pages.

    Helpers behave more like a method than the other constructs.

    Partials, layouts, sections, all use the same rendering and while they share quite a bit of similarities, there can be differences when using Render vs RenderPartial, making it mandatory to separate the View from Partial View architecturally.

    Standard view should not be called from one of the Render methods, as they are returned as ActionResults from the controller.

    These are just some of the reasons why there are many variations of a view.

  • Ivan said

    I have a problem with
    <div>
    @Html.RenderPartial("_FeaturedProduct")
    </div>
    It doesn`t work.
    @{Html.RenderPartial("_FeaturedProduct"); }
    But this one work fine

  • Rachel said

    Ivan,

    Oops! I've left out the {} in the post. Thanks for pointing out the syntax error, other readers will appreciate it.

  • David said

    Thanks for your article. How do you render a partial view that is located/associated with a different controller?

  • Rachel said

    David,

    There are a few overloads on the ActionLink method in the view to point to a different ocntrollers that you can use

    If you want it to run on the server side, you can return an ActionResult that points to a different view: return View("differentViewName");

    Additionally you can return a RedirectResult which will force it to a different controller:
    return RedirectToAction("Index");

  • David said

    My apologies for not wording the question better.

    In the View, if you use @Html.Partial("KeywordsInUse", Model.SelectedSubject.Keywords), this accesses the partial view that is associated with the control that got you to the view in the first place. So the question is, how do you render a partial view that is associated with a different controller?

  • Rachel said

    David,

    You can do something like this:
    @Html.Partial(@"~/Views/SomeOtherSetofViews/SomePartial.cshtml")

    Basically, you're just putting the full path of the view in there, bypassing any controllers.

  • TN Goti said

    This is nice post. It's really helpful for me as well as this link
    http://www.mindstick.com/Articles/94935ac3-7f7b-4c51-8d11-d00534036e7b/?View%20in%20ASP.NET%20MVC
    also helped me to complete my taask.

    Thanks

  • Steve said

    Hi, I've got a partial view that is basically a login box, that is being included via Html.Partial("_LogonPartial") on the main layout. The login box looks fine but when I click on submit the controller never gets called, nor does it raise any exceptions! It also looks like the data is getting posted as a GET rather than a POST (i.e. the password and user Id are now visible in a query string after the submit has been clicked on). The Partial View looks basically like this

    @model PocketStaff.Web.Models.LogOnModel

    @using (Html.BeginForm("Logon","Account"))
    {


    <div id="login">
    <h2>
    LOGIN</h2>

    @Html.TextBoxFor(m => m.UserName)
    @Html.ValidationMessageFor(m => m.UserName)
    </div>
    <div id="password">
    @Html.PasswordFor(m => m.Password)
    @Html.ValidationMessageFor(m => m.Password)
    </div>
    <div id="enter">
    <input class="loginButton" id="LoginButton" type="submit" value="ENTER" />
    </div>
    <div id="failed">
    </div>
    </div>
    }

    The Logon on the AccountController never get's called! :-O Have you got any ideas why not?

    Thanks in advance!

  • ray said

    @Rachel,
    Please fix it in the article.

    Rachel said on Sep 23 2011 at 11:49 AM
    Ivan,

    Oops! I've left out the {} in the post. Thanks for pointing out the syntax error, other readers will appreciate it.

  • Rachel said

    Ray,

    When I republish the old posts I'll edit this and others. Until then posts will use comments for corrections.

  • Rachel said

    Steve,

    Try this in your BeginForm to force a POST
    http://msdn.microsoft.com/en-us/library/dd460344.aspx
    Basically just a 3rd argument stating such in the code.

    I think that should do it for you. I don't see anything else in the code off hand that could cause an issue.

  • T said

    Rachel.

    I must overlooking something simple here... this is a super easy scenario, and yet I can't bind a complex type to ViewBag.

    The situation is not complex enough to justify creation of a ViewModel object, and quite simply it should work...

    // Controller
    public ActionResult() { ViewBag.User = new User{ /* properties initialized here */}; return View(); }

    // View
    @{ var user = ViewBag.User; /* user is null */ }

    I miss/misuse something? My eyes are tired today.

  • Octavian said

    Thanks Rachel, well done written.
    there many smart people in this world but there are only a handful of them could explain in a simple and effective way. I guess this what is we call a teacher :-).
    Thanks again, I'll definitely follow you on this blog.

  • Küstenpatent said

    This is a great inspiring article. I am pretty much pleased with your good work. You put really very helpful information. Keep it up. Keep blogging. Looking to reading your next post.

  • usman said

    sir,
    can we Share the data among partialview
    e.g i am calling a partial view from view then for that partialview i need to call another partialview
    i want this bcz i want to shw the sub categories of that categories after selection any help!!!!

  • Rachel said

    Usman,

    From your description you need a cascading drop down.
    See the link below, it will get you started. Multiple partial views will not work in this context.

    http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/CascadingDropDown/CascadingDropDown.aspx

    PS - I am a Ms. :)

  • Nanodots said

    I am often to blogging and i really appreciate your content. The article has really peaks my interest. I am going to bookmark your site and keep checking for new information.

  • Sheir said

    I am new to the MVC3 + Razor and am wondering if a main view can use more than one partial views where some partials are a Form (ie Html.BeginForm() or Ajax.BeginForm()) and each has its own model
    (ie one partial has Settings as its model class while another partial has JobStatus as its model class).
    Is that possible?

    Also what is the difference between the Html and Ajax BeginForms??

  • Rachel said

    Sheir,

    Yes, you can have multiple partials and they can contain HTML forms. Another solution (that I would suggest) is to look at using a ViewModel instead, as that's how you mix data from different sources to present in the view.

    http://rachelappel.com/use-viewmodels-to-manage-data-amp-organize-code-in-asp.net-mvc-applications

    An Ajax form an HTML form are the same except the ajax form will do a request for JSON data vs the standard HTTP Response. So, it's basically just the way to do AJAX in ASP.NET MVC.

    Rach

Comments have been disabled for this content.