Partial views in ASP.NET MVC

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.


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.


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.


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}
            Our Featured product:<br />
    </div>    <div>
            Now discounted to $@String.Format(“{0:F}”, ((decimal)ViewBag.FeaturedProduct.Price)-100)
        @Html.ActionLink(“Featured Product Details”, “Details”, new { id = ViewBag.FeaturedProduct.ProductId })
        <img class=“featuredProduct” src=@Href(“~/Content/Images”)/@ViewBag.FeaturedProduct.ImageName” alt=Featured Product”/>

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:



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


Introducing Razor

Introducing MVC Development w/the Razor View Engine

Razor View Syntax

When to use ViewBag, ViewData, or TempData in ASP.NET MVC 3 applications

“When should I use a ViewBag vs. ViewData vs. TempData objects?” — a frequent question in online forums, during presentations, and at events. There are enough similarities and differences between these objects that warrant a closer look to see exactly how you can use each of these objects while developing MVC applications.

All three objects are available as properties of both the view and controller. As a rule of thumb, you’ll use the ViewData, ViewBag, and TempData objects for the purposes of transporting small amounts of data from and to specific locations (e.g., controller to view or between views). Both the ViewData and ViewBag objects work well in the following scenarios:

  • Incorporating dropdown lists of lookup data into an entity
  • Components like a shopping cart
  • Widgets like a user profile widget
  • Small amounts of aggregate data

While the TempData object works well in one basic scenario:

  • Passing data between the current and next HTTP requests

If you need to work with larger amounts of data, reporting data, create dashboards, or work with multiple disparate sources of data, you can use the more heavy duty ViewModel object. See my detailed blog post on ViewModels for more details on working with ViewModels.

ViewData & ViewBag objects

  • ViewData
    • ViewData is a dictionary object that you put data into, which then becomes available to the view. ViewData is a derivative of the ViewDataDictionary class, so you can access by the familiar “key/value” syntax.
  • ViewBag
    • The ViewBag object is a wrapper around the ViewData object that allows you to create dynamic properties for the ViewBag.

Both the ViewData and ViewBag objects are great for accessing extra data (i.e., outside the data model), between the controller and view. Since views already expect a specific object as their model, this type of data access to extra data, MVC implements it as a property of both views and controllers, making usage and access to these objects easy. 

The syntax and usage of the ViewBag, ViewData, and TempData objects are outlined in the following code sample, which populates a featured product object that a view renders as in a bakery’s home page:

public class HomeController : Controller


    // ViewBag & ViewData sample

    public ActionResult Index()


        var featuredProduct = new Product


            Name = "Special Cupcake Assortment!",

            Description = "Delectable vanilla and chocolate cupcakes",

            CreationDate = DateTime.Today,

            ExpirationDate = DateTime.Today.AddDays(7),

            ImageName = "cupcakes.jpg",

            Price = 5.99M,

            QtyOnHand = 12



        ViewData["FeaturedProduct"] = featuredProduct;

        ViewBag.Product = featuredProduct;

        TempData["FeaturedProduct"] = featuredProduct;  


        return View();



The Index.cshtml view renders the Product object by accessing the code with the same syntax as in the controller. Notice that you’ll have to cast the ViewData and TempData objects, but not the ViewBag.

@using FourthCoffee.Models;


    ViewBag.Title = "Home Page";

    var viewDataProduct = ViewData["FeaturedProduct"] as Product;

    var tempDataProduct = TempData["FeaturedProduct"] as Product;                


<h2>Welcome to Fourth Coffee Bakery</h2>


    <a href="/Products">

    <img src='@Url.Content("\\Content\\Images\\cake.jpg")' alt="Fourth Coffee Bakery"/>    



        Today's Featured Product is!

        <br />





    @Html.ActionLink("Test Tempdata","Featured")


The ViewBag object lets you add dynamic properties to it which makes it a very versatile tool.

Although all three display something when this view renders, but the TempData can be troublesome when used in this manner, and here’s why…


TempData is meant to be a very short-lived instance, and you should only use it during the current and the subsequent requests only! Since TempData works this way, you need to know for sure what the next request will be, and redirecting to another view is the only time you can guarantee this. Therefore, the only scenario where using TempData will reliably work is when you are redirecting. This is because a redirect kills the current request (and sends HTTP status code 302 Object Moved to the client), then creates a new request on the server to serve the redirected view. Looking back at the previous HomeController code sample means that the TempData object could yield results differently than expected because the next request origin can’t be guaranteed. For example, the next request can originate from a completely different machine and browser instance.

As described below, the syntax for using TempData is the same as ViewData.

// TempData sample

public ActionResult Featured()


    var featuredProduct = new Product


        Name = "Assorted Cupcakes",

        Description = "Delectable vanilla and chocolate cupcakes",

        CreationDate = DateTime.Today,

        ExpirationDate = DateTime.Today.AddDays(7),

        ImageName = "cupcakes.jpg",

        Price = 5.99M,

        QtyOnHand = 12



    ViewData["FeaturedProduct"] = featuredProduct;

    ViewBag.Product = featuredProduct;

    TempData["FeaturedProduct"] = featuredProduct;


    //After the redirect, the ViewBag & ViewData objects are no longer available

    //Only TempData survives a redirect


    return new RedirectResult(@"~\Featured\");


However, once the controller redirects, the ViewBag and ViewData will contain null values. If you inspect the TempData object with debugging tools after the redirect you’ll see that it is fully populated with a featured product. This is because the redirect is that only, subsequent, request, so only it can access the TempData object without worry.

@using FourthCoffee.Models;

@model FourthCoffee.Models.Product


    ViewBag.Title = "Details";

    var featuredProduct = TempData["FeaturedProduct"] as Product;


The customary Session object is the backing store for the TempData object, and it is destroyed more quickly than a regular session, i.e., immediately after the subsequent request. Because of its short lived scope, it’s great for passing error messages to an error page.

Greg shackles has a very comprehensive blog post that covers just about everything you need to know about TempData.

Now that you’ve seen how and when to use ViewData, ViewBag, and TempData objects, you might be wondering what to do when using larger sets of data or more complex scenarios. Fortunately, MVC has ways to deal with these commonly needed scenarios.

Thinking outside the ViewBag

Your requirements might need you to represent the following types of data, which do not fit in well when using ViewBag, ViewData, or TempData objects. The MVC 3 framework contains ViewModel objects for when you need more than ViewData. The type of data that suits ViewModels well is as follows:

  • Master-detail data
  • Larger sets of data
  • Complex relational data
  • Reporting and aggregate data
  • Dashboards
  • Data from disparate sources

You’ll likely run into these or similar scenarios during the app development process.


The ViewData and ViewBag objects give you ways to access those extra pieces of data that go alongside your model, however for more complex data, you can move up to the ViewModel. TempData, on the other hand, is geared specifically for working with data on HTTP redirects, so remember to be cautious when using TempData.

Introducing MVC Development w/the Razor View Engine for Visual Studio Developers

The Razor View Engine is a precise, useful, light language that enables you to create views for MVC projects in ASP.NET still while keeping a separation of concerns, ability to test, and pattern based development.  ASP.NET MVC developers looking for a more concise syntax now have another option that’s built-in (of course, there are many 3rd party view engines out there) with the language being a familiar light version of C#.

The Razor View engine is used to create WebMatrix sites or Visual Studio MVC applications.  When using ASP.NET MVC with either engine, you’ll stick to a style of development called “convention over configuration”, meaning that you’ll use certain naming conventions to name files, models, views, controllers, and other key application elements rather than storing lots of metadata about these same elements in a configuration file.  When using MVC in Visual Studio 2010, it’s is setup so that you’ll be guided to use convention over configuration, which becomes evident when exploring an ASP.NET MVC project.

Getting Started

Before you start, go and download these two things (as of this post; things are subject to change – these could end up in VS at some point):

You can also find the Razor Syntax Highlighter by choosing Extensions Manager from the Visual Studio Tools menu.  Once installed, MVC 3 project templates are available from Visual Studio.  The MVC 3 Web Application template allows you to use either the Web Forms View Engine or the Razor View Engine, while MVC 2 Applications contain only the WF View Engine.


When creating a new MVC 3 project a new dialog box appears asking which application type, view engine, and testing framework you’d like to use.  You can and should add a test project so you can test your code, then actually write some tests in it.   The image below demonstrates selecting the internet application project template using Razor as the view engine, as well as the test framework.  The internet application MVC template adds in ASP.NET membership & security features to the project by creating the necessary model, view and controller for logging on and registering as a site user.


Verify that the project is created with three folders, one each for Models, Views, and Controllers which is the same folder structure as a MVC 2 site.  The project also contains auxiliary folders and files needed for the application such as the Content & App_Data folders.   Since this is an MVC application using the Razor View Engine, you will see a different file extension – .cshtml.  The .cshtml files are Razor View Pages written using the Razor View Engine.  If you’re not familiar with Razor syntax, I’ve blogged about it here, and the online documentation has more information as well.


The application template sets up some models, views and controllers to start with, and is now ready for new models, views, and controllers.  I’ve found the easiest way to work with MVC in VS is to start with the model, move to the controller, then create the view, so we’ll look at models first.


A model is a representation of an underlying data store.  Models can be almost anything from any data source; EF or Linq2Sql Models, or a simple class.  The code the builds the model below consists of two classes, a ProductModel class and a Product class.  The ProductModel class returns a List<t> of Product objects in a property aptly named Products that represents one or more products in the data store .  Product objects contain ProductNumber, Name and Price properties and represent an individual product in the data store.  The model code representing these product objects is below:

using System.Collections.Generic;
namespace AdventureWorks.Models
    public class ProductModel
        public List<Product> Products { get; set; }
        public ProductModel()
            Products = new List<Product>();
            this.Products.Add(new Product("AB-00-J1" ,"Super Fast Bike" ,1000M));
            this.Products.Add(new Product("EE-9-OL"  ,"Durable Helmet"  ,123.45M));
            this.Products.Add(new  Product("MMM99-54" ,"Soft Bike Seat"  ,34.99M));

    public class Product
        public Product(string productNumber, string name, decimal price)
            Name = name;
            Price = price;       
        public string ProductNumber { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }

Models are handed over to views by controllers so the views can render the data from the model.  The model will extend business logic (of course, this is a simple example, business logic will likely be spread out into other applications & tiers). Models also provide validation information to the view via metadata & code.  You can add the model to the \Models folder or you can reference an external data model library.  In this case, the model’s been added to the \Models folder.


Controllers are objects that inherit from the System.Web.Mvc.Controller class that match models with views.  During incoming requests, MVC’s routing system kicks in and determines which controller method to use based on routing code set in the global.asax.cs file.  A default route is set in the global.asax.cs file that works for most of the routes you’ll need, however, if need be then you can modify/add/delete your own routes.

Staying within convention, controller code files should go in the \Controllers folder. The controller class must follow the naming convention of YourNameController, i.e., ProductsController.  The controller’s Index method, again following convention, must be named the same name as its view but without the file extension.  By following this pattern, the controller can have multiple actions that deliver data to multiple views, making code easier to write, maintain, and test.

namespace AdventureWorks.Controllers
    public class ProductsController : Controller
        public ActionResult Index()
            ProductModel p = new ProductModel();           
            return View(p.Products);

By observing the previous code sample and the conventions that it follows, it’s clear that the Index method maps to the \Views\Products\Index.cshtml view.  The Index() method’s return type is an ActionResult from the System.Web.Mvc namespace.  There’s many different results that you can use for different scenarios such as ContentResult, FileResult, RedirectResult, ViewResult and others depending on your view’s needs


Views are a mechanism to format and render data in a browser from the model, as specified by the @model attribute (or @inherits) at the top of the view.  Views in ASP.NET MVC with either the ASPX or Razor View engines use a code-based way to render the page rather than relying on declarative controls, which create tight coupling and are hard to test.  Using the MVC approach creates cleaner output in the browser as well as cleaner and more terse syntax in the views as well.  Views are meant to only render the markup, code and data; they’re not meant as a place to store business logic. The model and tiers accessed by the model, are the appropriate places to host business logic.  The view can have a small amount of UI validation logic,as a first line of defense for input sanitation, e.g., required, regex and range validators.

To add a view to your project, right click on the controller and select Add View.


Visual Studio will need some information about the view, which is supplied in the Add View dialog box:

  1. Specify whether you want a strongly-typed view or not.  Creating a strongly-typed view allows you to refer to the underlying data structures in the classic syntax.
  2. Specify the view data class.  The dropdown list displays classes in your project that are part of the data model.
  3. Specify the view engine.  ASPX and Razor are the options.
  4. Specify the view content.  Choices are list, details, edit. etc…  Choosing this option creates .cshtml or .aspx view pages that do page rendering for you.


Here’s what choosing these options will produce in a Razor view page named \Views\Products\Index.cshtml:

@model List<AdventureWorks.Models.Product>

View.Title = "Index";
Layout =

@Html.ActionLink("Create New", "Create")
<th>Product Number</th>

@foreach (var item in
Model) {
@Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
@String.Format("{0:F}", item.Price)

Since the view is strongly typed, the data structure can be accessed as it is – an object with properties.  The code above loops through the model and renders a <TR> for each entity that the model holds along with <TD> tags and the actual data in them (ProductNumber, name and Price).  The result is a simple list of the three products in model with accompanying action links.


The HTML source shows a clean, precise table rendered to the browser.



Rendering a list of products is very easy using MVC and the Razor View Engine, as is updating/manipulating the data (logically what you’d do next if following this example).   If you’re digging deeper into learning MVC w/Razor the next topics you’ll want to get into are jQuery and HTML validation helpers for client side validation, and decorating the model with data annotations (also for validation).  The MVC web site has a ton of great examples and tutorials.

Although many ASP.NET MVC samples use the ASPX/Web Forms view engine they’re easily compared & converted to razor pages – so don’t avoid them, it’s still a great way to learn both MVC w/Razor and the ASPX engine.

Add HTML5 Geolocation plus Bing Maps into ASP.NET MVC views

The Bing Maps API is a free, easy to use API, that allows you to incorporate mapping features into your ASP.NET MVC or application by using Web standards such as JavaScript, and the now supported HTML5 Geolocation.

Bing Maps and ASP.NET MVC

A Bing maps API key is required when using the API. The Bing Maps key allows you to access Geolocation data, and to manipulate an in-view Map object with JavaScript via the Bing Maps API. The Bing Maps Developer Portal is where you can get a key by registering with your Windows Live ID.

Once you’re set with a key, you’ll need these files in your MVC project to develop with Bing Maps:

\Scripts\YourBingMapsScript.js – This file contains your script that works with Bing Maps & Geolocation.

\Content\Site.css – A small bit of CSS is required to style the Map

\Views\BingMaps\Index.cshtml – The MVC view that contains the Bing Map HTML

Since the code is HTML &CSS that conform to Web standards, the bulk of the lives is in the .js file and/or the view. Although using MVC, the model and controller are not necessary for manipulating maps with client side script, but don’t throw out the model and controller yet, as you will need them to work with other data.

The Bing Maps Interactive SDK

If you’re writing code that uses Bing Maps, the Interactive Bing Maps SDK is a “must visit” Web site. By choosing the options on the left of the page, the Bing Maps Interactive SDK creates usable JavaScript, and a “View HTML ” button that exposes the page source.



The Bing Maps API & SDK contain more than an interactive website. Bing Maps development gives you access to many productive development tools such as:

  • The Bing Maps AJAX Control (multiple versions)
  • The Bing Maps iOS Control
  • A Bing Maps Silverlight Control
  • SOAP and REST services
  • More…

You can use the Bing Maps Interactive API to create the equivalent code as the samples shown in this post.

Render Bing Maps in MVC views with the Bing Maps AJAX control.

While it’s called the Bing Maps AJAX control, it’s not a control at all, but a JavaScript library instead. HTML and client side script (JavaScript, jQuery, etc…) are the enabling technologies for Bing Maps on the ASP.NET (or any Web) platform. To reference the Bing Maps AJAX Control, your view needs the <script> reference below.

<script src="" type="text/javascript"></script>

If you plan to use the Bing Maps AJAX control in multiple views, the <script> reference can go in the _Layout.cshtml file, otherwise you can add it to the required views or a different layout page. Inside a view, a <div> element should contain and display the map, and is also the DOM object that you manipulate in code, so it needs an id attribute.

<div id="map"></div>
Since the browser renders a tiny <div> by default, some CSS is necessary, such as the position, width, and height, in which to create a suitable DOM shape for maps. You can save the CSS in the \Content\Site.css file, or its own file, for reusability across views.  
    width: 500px; 
    height: 500px; 

After the HTML is in place, you can write code to capture the user's positional data to display a Bing map showing the location, nearby restaurants, or other information requested by the user. 

Display a Bing Map with a Pushpin.

You first need positional data from the user before displaying the map. Once you have the positional data points, i.e., latitude and longitude, you can add a Bing Map to any MVC view. To learn how to obtain positional data for your Web site or app, see this post on creating location aware Web sites with the HTML5 Geolocation.

The code below retrieves the latitude and longitude coordinates from the position argument of a showMap method, then creates an instance of a Map object the position, credentials, center, map type, and zoom level. The code continues on by centering the Pushpin to represent the user’s location in the map.

function showMap(position) {
    var latitude = position.coords.latitude;
    var longitude = position.coords.longitude;
    var map = new Microsoft.Maps.Map($("#map")[0],
        credentials: "Your Bing Maps API Key",
        center: new Microsoft.Maps.Location(latitude, longitude),
        mapTypeId:   Microsoft.Maps.MapTypeId.road,
        zoom:        10
    var center = map.getCenter();
    var pin = new Microsoft.Maps.Pushpin(center, { width: 50, height: 50, draggable: false });

The result should look something like this (but with your coordinates):


Should you want to customize the Pushpin icon, just change the Pushpin construction arguments, and pass in the path and name of the graphics file (.png, .jpg., and standard Web formats).

var pin = new Microsoft.Maps.Pushpin(center, {icon: 'CustomPushpin.png', width: 50, height: 50, draggable: true}); 

Customizing the map further by adding an Infobox, which is a small rectangle with information about a particular location, takes only a few lines of code. Make sure the clear method is run before pushing an Infobox onto a map or the latest Infobox, Pushpin, or other object will overlay the previous.

 var infoboxOptions = {title:'Bing Maps Rock!', description:'Add an Infobox to a map with very little JavaScript!'}; 
 var defaultInfobox = new Microsoft.Maps.Infobox(map.getCenter(), infoboxOptions );    

The above code creates an Infobox on the map similar to the one shown here:


These are just a few simple, but core examples, of what you can do with Bing Maps. For more information on developing for Bing Maps, see below in the Summary & Resources.

Summary & Resources

The Bing Maps AJAX control is a handy library you can use to add geo-interactivity to your Web sites with little code. Additionally, you can incorporate other APIs to make full featured location aware mapping apps.

Use the W3C Geolocation API to create location aware Web sites

The Bings Map control (Bing Maps API)

Bing Maps Articles

Customizing Bing Maps Pushpins

G. Andrew Duthie demonstrates bing maps in action with

ASP.NET MVC ActionResults explained

Action results are an important part of the ASP.NET MVC controller system, and definitely worth taking a good look at. Understanding how they work gives you many more choices in MVC and that will certainly help make your code better.

What is an ActionResult?

An ActionResult is a return type of a controller method, also called an action method, and serves as the base class for *Result classes. Action methods return models to views, file streams, redirect to other controllers, or whatever is necessary for the task at hand. The controller takes on this responsibility to connect system components, acting as a traffic cop.

There are many derived ActionResult types you can use to return results that are more specific for a particular view. You can quickly access the derived types of the ActionResult during development by hovering over an ActionResult in an action result’s method signature then expanding the type tool window, to see what *Results the ASP.NET Framework provides.To get a deeper look at what exactly an ActionResult type is and how it works, running the code with a breakpoint set at the end of an action result method will get the information we want. Inspecting the image below of the Watch window shows some of the properties that you can tap into that ActionResults return.

Notice the Model, TempData, ViewBag, and ViewData properties. Drilling into the Watch window even further exposes the Model property’s strongly typed collection of objects.


These objects contain everything you need when working in the view. Of course, the Model is the most heavily used object, containing our application’s schema and data. The TempData object holds data between multiple controllers, while ViewBag and ViewData objects holds data between controllers and/or views.

Since the Model property is the actual model the view uses to render the data, its data type should align with the type specified in the @model directive in the target view. As pointed out in the image above, the Model property contains a strongly typed list of Product objects (or whatever you’re returning), matching the view’s model.

Looking in the Watch window shows that the runtime converts the ActionResult to a ViewResult, however you’ll want to be more specific during design time. Swapping ActionResults for more specific/derived classes, for example, a ViewResult, produce the exact same object structure as the ActionResult. With this in mind, using more specific types increases code accuracy, maintainability, and even performance as the compiler has a much better idea of what should happen at compile time, rather than at the last minute at runtime, since no runtime conversion happens.

Action methods, action results & routing

Action methods and the routing system work together in every MVC application. MVC does this by using a set of conventions, defined as routing patterns in the global.asax.cs file. These patterns connect HTTP requests with controllers and action methods. As an HTTP Request enters the routing system, it determines which controller should serve data to which view (if any).

The global.asax.cs defines the default routing pattern, {controller}/{action}/{id}, as described in more detail here:

public static void RegisterRoutes(RouteCollection routes)

    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults

Picking apart each piece of the route pattern is a great way to digest what the routing system is doing…

  • {controller} Controller maps a part of the URL to the name of the controller class. For example, a class named ProductsController, will map to URLs that start with /Products (after the domain of course). ASP.NET automatically drops the word “Controller” from the URL so is it’s more user friendly, e.g., /Products vs. /ProductsController.
  • {action} Action maps a part of the URL to the individual methods inside controllers. Therefore the ProductsController.Edit(…) and ProductsController.Details(…) methods align with the /Products/Edit and Products/Details URLs, respectively. Action maps without any parameters, since the next route pattern, id, defines them.
  • {id} Id maps to an identifier, such as a product id or a product name. These are controller action method parameters, so the value at the end of the URL is generally the value of the method’s argument. For example, /Products/Edit/2 matches up with the id argument in ProductsController.Edit(int id). The controller methods normally use this id to query for a single record with a matching id to return to the view.

Below is a table detailing the mappings between routes, controllers, action methods and their parameters.

Action Method Route {controller}/{action}/{id} HTTP POST/GET
public ActionResult Index() { } /Products GET
public ActionResult Details(int id) { } /Products/Details/id GET, values in URL
public ActionResult Edit(int id) { } /Products/Edit/id GET, values in URL
public ActionResult Edit(int id, FormCollection collection) { }
/Products/Edit/id POST, values in FormCollection
public ActionResult Create() { } /Products/Create GET
public ActionResult Create(FormCollection collection) { }
/Products/Create POST, values in FormCollection
public ActionResult Delete(int id) { } /Products/Delete/id GET, values in URL
public ActionResult Delete(int d, FormCollection collection) { }
/Products/Delete/id POST, values in FormCollection

You may have noticed that the Edit, Create, and Delete action methods come overloaded as pairs, and an [HttpPost] attribute decorates one method in each pair. Since [HttpGet] is the default, the other method doesn’t need to be marked. Additionally, all methods decorated with the [HttpPost] attribute are meant to accept HTML input fields located between the <form> tags. The collection parameter of type FormCollection[1] contains all the input fields from the <form> of the HTTP Post.

Every method in a controller class returns an ActionResult by default; however, some actions will be more optimized, clear, or accurate in the code, if we are to specify a more specific action results, for instance, a ViewResult, rather than an ActionResult. Action result methods can also designate that its result will return something other than data for a view, e.g., a HttpNotFoundResult or an HttpStatusCodeResult, as shown in the code below:

Returns an HTTP 404 Not found error:

public HttpStatusCodeResult NotFound()
    var result = new HttpStatusCodeResult(404);
    return result;

Redirects to a separate view altogether:

public RedirectResult Create(FormCollection collection)
    // code to save form data ...     
    return new RedirectResult("Home/Index", false);

There’s many more ActionResult types to explore. Check them out and find something that meets the needs of your controller and/or view.


ActionResults are a key component to ASP.NET MVC, so understanding them is essential for MVC application development. Whether you need to make AJAX calls, redirect, return a file stream, or just return data to a view, ActionResults are right there in the center of all the……action.

[1] I recommend rather than using FormCollection, you should use a strongly typed parameter or multiple, differently typed parameters that match to data types in the HTML form. Look forward to a blog post soon to demonstrate this.