Reintroducing for and foreach

In this recipe, we will take a look at how to iterate over a collection of data using for and foreach. In this recipe, we will use NBuilder to create a list of Product classes for us to work with. Then we will build three views that will iterate over the collection in different ways. We will show how to iterate over a collection of products pulled from ViewData using foreach. Then we will see how we can iterate over the Model property of a strongly typed view. And finally, we will create another strongly typed view and use a for statement to iterate over the collection.

How to do it...

Initial bits...

  1. The first thing that we need to do is create a new ASP.NET MVC project. Then we will add a reference to NBuilder (in the dependencies folder of the download).
  2. Next, we will create a new class in the Models folder of our application called Product. This class will be used for creating a collection of data for our iteration examples.

    Models/Product.cs:

    public class Product
    {
    public int ProductId { get; set; }
    public string Name { get; set; }
    public double Price { get; set; }
    public string Description { get; set;}
    public DateTime CreateDate { get; set; }
    }
    
  3. As we are going to have three examples in this recipe, we will need to centralize the code that we will use to generate the list of products. We will do this by creating a ProductRepository class in the Models folder. This class will use NBuilder to do the generation work for us.

    Models/ProductRepository.cs:

    public class ProductRepository
    {
    public List<Product> GetProducts()
    {
    List<Product> result = Builder<Product>
    .CreateListOfSize(30)
    .WhereAll()
    .Have(x => x.Description = @"...long lorem ipsum string...")
    .Build()
    .ToList();
    return result;
    }
    }
    

foreach over ViewData collection

  1. Now that we have a working repository to get a list of data from, we can create our first example of a foreach loop. Start by opening the home controller. In the existing Index view, we will add a line of code passing a collection of Products into the ViewData dictionary.

    Controllers/HomeController.cs:

    ViewData["Products"] = new ProductRepository().GetProducts();
    
  2. Then we need to open up the Index view corresponding to the Index action we just added the code to. Then remove all of the fluff that the template adds for us. Now we will add a line of code to grab the list of products out of the ViewData collection.

    Views/Home/Index.aspx:

    <% List<Product> products = ViewData["Products"] as List<Product>; %>
    
  3. With reference to our collection of products, we can work on the iteration aspect of our recipe. Iteration code is pretty quick and to the point.

    Views/Home/Index.aspx:

    <% foreach (Product p in products) { %>
    ...
    <% } %>
    
  4. To finish off this portion, we will need to add our formatting code and the output of our data.

    Note

    There is a new shorthand syntax in MVC 2 that allows us to perform an Html.Encode. There is the previous syntax <%= that allows us to write data as if we had used Response.Write. Then there is the new <%: syntax. This <%: variant encodes the data prior to spitting it out, allowing us to remove all the <% Html.Encode statements that we would have to use. But as Visual Studio's code generator still uses <%= Html.Encode, we will leave it as it is.

    Views/Home/Index.aspx:

    <div class="display-label">ProductId</div>
    <div class="display-field"><%= Html.Encode(p.ProductId) %></div>
    <div class="display-label">Name</div>
    <div class="display-field"><%= Html.Encode(p.Name) %></div>
    <div class="display-label">Price</div>
    <div class="display-field">
    <%= Html.Encode(String.Format("{0:c}", p.Price)) %></div>
    <div class="display-label">Description</div>
    <div class="display-field"><%= Html.Encode(p.Description) %></div>
    <div class="display-label">CreateDate</div>
    <div class="display-field">
    <%= Html.Encode(String.Format("{0:g}", p.CreateDate)) %></div>
    <hr />
    
    

foreach over strongly typed view model

  1. With the iteration over ViewData completed, we can now take a look at how things differ when using a strongly typed view instead. To start this portion of the recipe, open the home controller. Then we will add a new ActionResult called ForEach. In this method, we will again get a list of products from our repository and return that collection to our view. This time though, we will not use the ViewData dictionary to pass out the data. Instead, we will pass it directly to the view.

    Controllers/HomeController.cs:

    public ActionResult ForEach()
    {
    List<Product> products = new ProductRepository().GetProducts();
    return View(products);
    }
    
  2. Next, we will look at the code generation that Visual Studio can do for us. Right-click on the method and choose Add View. This will open the Add View dialog.
    foreach over strongly typed view model
  3. In the Add View dialog you have lots of options. We will leave the view name as it is (the view that will be generated). Then we will check the Create a strongly typed view box. Next, we will choose the type that we want the view to be typed to (MvcApplication1.Models.Product in this case). In the View content: drop-down list, there are all sorts of good options...we will choose to generate a Details view. Then you can choose to use a master page for your view. Click on Add.
  4. You may have noticed that we chose to add a Product but we returned a product list in our action definition. To fix this mismatch, we will need to edit the declaration of our generated view from expecting one product to instead expect a collection of products.
    Inherits="System.Web.Mvc.ViewPage <MvcApplication1.Models.Product>"
    

    to

    Inherits="System.Web.Mvc.ViewPage<List <MvcApplication1.Models.Product>>".
    
  5. Now we will need to create our foreach statement wrapped around our generated details view.

    Views/Home/ForEach.aspx:

    <% foreach (Product p in Model) { %>
    ...
    <% } %>
    
  6. Then we need to edit the details view code to use the p reference in place of the Model object. Change:
    <%= Html.Encode(Model.ProductId) %>
    

    to

    <%= Html.Encode(p.ProductId) %>
    

    (The same for all other Model references.)

for over strongly typed view model

  1. With the example of ViewData and strongly typed view Model iterations using the foreach statement, we can now look at a strongly typed view Model example using the for statement. To start this example, we need to create another new action called For. This method will also return a list of products from our ProductRepository.

    Controllers/HomeController.cs:

    public ActionResult For()
    {
    List<Product> products = new ProductRepository().GetProducts();
    return View(products);
    }
    
  2. As in the last example, we will generate a view by right-clicking on the method and choosing Add View. Name this view For. All the other options will be the same as before.
  3. We will need to change the inherited type for this view as we did in the last example by changing:
    Inherits="System.Web.Mvc.ViewPage <MvcApplication1.Models.Product>"
    

    to

    Inherits="System.Web.Mvc.ViewPage<List <MvcApplication1.Models.Product>>".
    
  4. Then we need to create our for statements.

    Views/Home/For.aspx:

    <% for (int i = 0; i < Model.Count; i++) { %>
    ...
    <% } %>
    
  5. With our for declaration in place, we then need to update the generated details view to reference an index in the collection of products, rather than referencing properties of a single product model. We will have to change all references of
    <%= Html.Encode(Model.ProductId) %>
    
    

    to

    <%= Html.Encode(Model[i].ProductId) %>
    
  6. Now you can hit F5 and view all three different manners of model iteration!

How it works...

The iteration over a collection is pretty standard to all languages. The syntax of each iteration style was the focus of this recipe. More importantly, how to reference the collection is what varies the most. For a quick recap:

  • In a non-strongly typed view we have to reference the collection in the ViewData dictionary and cast it out as the type we expect.
    List<Product> products = ViewData["Products"] as List<Product>;
    foreach (Product p in products)
    p.ProductId
    
  • For a strongly typed view there is no casting required. However, you need to know that the collection is contained in the Model rather than in the ViewData.
    foreach (Product p in Model)
    p.ProductId
    
  • And finally, the syntax for a strongly typed view using the for syntax is also different.
    for (int i = 0; i < Model.Count; i++)
    Model[i].ProductId
    

There's more...

Now there is the question of which method of iteration you use, for, or foreach? This is not the place to address that. Understand that the for syntax is the most efficient, but the foreach syntax is considerably more readable! Take a look at Jon Skeet's post on the performance implications between the two (http://msmvps.com/blogs/jon_skeet/archive/2009/01/29/for-vs-foreach-on-arrays-and-lists.aspx).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset