Book Image

ASP.NET MVC 2 Cookbook

Book Image

ASP.NET MVC 2 Cookbook

Overview of this book

ASP.NET MVC, one of the latest web development platforms from Microsoft, brings the power of MVC programming to ASP.NET development. It simplifies the task of application development and maintenance for developers. However, ASP.NET MVC is filled with so many features that developers end up looking for solutions to the many problems that are encountered in their routine development tasks.ASP.NET MVC 2 Cookbook will provide solutions for the very specific problems that are encountered while developing applications with the ASP.NET MVC platform. It consists of many recipes containing step-by-step instructions that guide developers to effectively use the wide array of tools and features of ASP.NET MVC platform for web development ASP.NET MVC Cookbook is a collection of recipes that will help you to perform your routine development tasks with ease using the ASP.NET MVC platform. In this book you will be walked through the solution to several specific web application development problems. Each recipe will walk you through the creation of a web application, setting up any Visual Studio project requirements, adding in any external tools, and finally the programming steps needed to solve the problem. The focus of the book is to describe the solution from start to finish. The book starts off with recipes that demonstrate how to work effectively with views and controllers – two of the most important ingredients of the ASP.NET MVC framework. It then gradually moves on to cover many advanced routing techniques. Considering the importance of having a consistent structure to the site, the book contains recipes to show how to build a consistent UI and control its look with master pages. It also contains a chapter that is packed with many recipes that demonstrate how to gain control of data within a view. As the book progresses through some exciting recipes on performing complex tasks with forms, you will discover how easy it is to work with forms to jazz up the look of your web site. Building large applications with ease is one of the prime features of the MVC model. Therefore, this book also focuses on tools and features that make building large applications easier to manage. As data plays an important role in the MVC architecture, there are ample recipes dedicated to cover data validation, access, and storage techniques. Finally, the book demonstrates how to enhance the user experience of your visitors by controlling the data at the application, session, caching, and cookie level. By the end of this book, you will have explored a wide array of tools and features available with the ASP.NET MVC platform
Table of Contents (16 chapters)
ASP.NET MVC 2 Cookbook
Credits
About the Authors
About the Reviewers
www.PacktPub.com
Preface

Rendering a child view with Html.RenderAction


In the previous recipe, we took a look at how you can split up the view code into multiple partial views to make managing presentation code easier and more reusable. In most cases, this is exactly what you will need, as a view usually has a view model that is specially built just for it. In our previous recipe, we took pieces of the overall view's model and pushed bits of it off to the partial views.

In other cases though you may have totally separate models that are displayed by separate views. Sometimes they may even be handled by different actions in different controllers. In this case, you might try to render an action directly and put the result of that view into another view. In this way, we won't have to worry about cross-pollinating models and views from various controllers.

How to do it...

  1. 1. Create a new MVC application.

  2. 2. Then we will create a quick model to play with. We need two distinctly different models to be able to demonstrate why we would need to render one action from within another. We will create a Post class to represent some blog posts. And we will create a Product class to represent a list of suggested products, which we will display next to our blog posts.

    Models/Post.cs:

    public class Post
    {
    public DateTime Created { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
    }
    

    Models/Product.cs:

    public class Product
    {
    public string Name { get; set; }
    public string Description { get; set; }
    public double Cost { get; set; }
    }
    
  3. 3. Then we need to create a couple of service classes from which we will generate a list of our new object models. We will create a ProductService class and a BlogService class. Each of these classes will have Get methods on them to get a list of the specific objects we need.

    Models/BlogService.cs:

    public class BlogService
    {
    public List<Post> GetPosts(int count)
    {
    List<Post> result = new List<Post>();
    for (int i = 0; i < count; i++)
    {
    Post p = new Post();
    p.Created = DateTime.Now;
    p.Title = "A really great post";
    p.Body = @"Lorem ipsum dolor sit amet, ...";
    result.Add(p);
    }
    return result;
    }
    }
    

    Models/ProductService.cs:

    public class ProductService
    {
    public List<Product> GetProducts(int count)
    {
    List<Product> result = new List<Product>();
    Random r = new Random();
    for (int i = 0; i < count; i++)
    {
    Product p = new Product();
    p.Cost = r.Next(5, 50);
    p.Name = "Really great product";
    p.Description = @"Lorem ipsum ...";
    result.Add(p);
    }
    return result;
    }
    }
    
  4. 4. Now that we have the ability to generate a list of working data, we can next turn our attention to creating two controllers to handle views for each of our two object types. We will create a BlogController and a ProductController. The BlogController will expose an Index action to show a list of recent blog posts. The ProductController will have a SuggestedProducts action that will return a list of products.

    Models/BlogController.cs:

    public class BlogController : Controller
    {
    public ActionResult Index()
    {
    return View(new BlogService().GetPosts(5));
    }
    }
    

    Models/ProductController.cs:

    public class ProductController : Controller
    {
    public ActionResult SuggestedProducts()
    {
    return View(new ProductService().GetProducts(7));
    }
    }
    
  5. 5. The next thing for us to do is to generate a view for each of our controllers. We will start with the ProductController, as its view is the easiest. For this controller, we will generate a strongly typed partial view based on a Product using the details view. Once the view is generated, we have to change the model from a single instance of Product to a List of Product. Then we need to wrap the details view that was generated with a loop.

    Views/Product/SuggestedProducts.aspx:

    <%@ Page Title="" Language="C#" Inherits= "System.Web.Mvc.ViewPage<List<MvcApplication1.Models.Product>>" %>
    <%@ Import Namespace="MvcApplication1.Models" %>
    <fieldset>
    <legend>Suggested Products</legend>
    <% foreach (Product p in Model) { %>
    <div class="display-field"><b><%: p.Name%></b></div>
    <div class="display-field">
    <i><%: String.Format("{0:C}", p.Cost)%></i>
    </div>
    <div class="display-field"><%: p.Description%></div>
    <% } %>
    </fieldset>
    
  6. 6. Now we need to generate our primary view, which will be responsible for showing a list of blog posts. In addition to displaying blog posts, we will also render the list of suggested products. Similar to our previous view, we will start by generating the view from the Index action of the BlogController. This will be a strongly typed details view based on the Post class. Once it is generated, we will need to wrap the generated view code with a table so that the list of blog posts can sit next to a list of suggested products. I also added a bit of styling to get things to line up a bit better.

    Views/Blog/Index.aspx:

    <h2>My Blog</h2>
    <table style="width:800px;">
    <tr>
    <td style="width:200px;vertical-align:top;">
    <!-- Suggested products... -->
    </td>
    <td style="vertical-align:top;">
    <fieldset>
    <legend>Recent Posts</legend>
    <%
    foreach (Post p in Model)
    { %>
    <div class="display-field"><b><%: p.Title%></b></div>
    <div class="display-field"><i>
    <%: String.Format("{0:g}", p.Created)%></i></div>
    <div class="display-field"><%= p.Body%></div>
    <% } %>
    </fieldset>
    </td>
    </tr>
    </table>
    
  7. 7. Now that we have our primary view created, we can turn our attention to rendering a list of suggested products. All that we need to do is add a call to Html.RenderAction where we currently have this comment <!-- Suggested products...-->. In order to make this call, we only need to specify the name of the action and the controller that we want to render.

    Note

    If, while rendering this recipe, you see two master pages, then the odds are that you didn't generate a partial view for your SuggestedProducts view!

    Views/Blog/Index.aspx:

    ...
    <td style="width:200px;vertical-align:top;">
    <% Html.RenderAction("SuggestedProducts", "Product"); %>
    </td>
    ...
    
  8. 8. Now you can run the application. Navigate to /Blog/Index and you should see a list of blog posts. Next to that you should also see a list of suggested products. Notice that our blog controller didn't have to know anything about products in order for it to use the SuggestedProducts view. This is the power of the RenderAction helper method.

How it works...

In this recipe, we saw how we can separate the logic that views require into multiple controllers while still being able to use those views together. This functionality is built into the MVC framework and exposed through the HtmlHelper class.

There's more...

Be aware that using this method has one gotcha. If you want to use output caching on the rendered view—don't. It won't work (at the time of this writing). You can put an OutputCache attribute on the SuggestedProducts view, but when you render the SuggestedProducts partial view from within the product's Index, the OutputCache attribute is simply ignored from the parent view. Check out the chapter on caching and you will find a workaround to this issue!