MVC – strongly typed views

In MVC4, we’ve seen that we can send data from the controller to a view by using the ViewBag, which is a dynamic C# object in which you can define properties of any data type.

Although this is a powerful technique, you might have noticed if you were typing in the code we gave in the last post for displaying the list of comic books in the view that Visual Studio’s Intellisense didn’t seem to be working. Here’s the code we typed in the last post:

<ul>
    @foreach (var comic in ViewBag.Comics)
    {
        <li>
                @comic.Title: <b>@comic.Volume</b> (@comic.Issue)
        </li>
    }
</ul>

The Comics property of the ViewBag was of type List<Book> (where Book is a model class that contains the properties of a comic book), so the foreach loop accesses each Book in turn and prints out its fields on the web page.

When you type the @comic. bit, ordinarily you’d expect Intellisense to pop up with a list of fields in the Book object, but here nothing happens. This is because VS has no way of knowing what the data type of ViewBag.Comics is until the program is actually run. That’s part of the beauty of a dynamic variable, but it also means that coding is more difficult.

A way around this is to use a strongly-typed view. We’ll pass the same data (a List<Book>) to the view, but we’ll do it in a way that lets the view know the data type of the object that is being sent to it.

The changes we need to make to the code are minimal, but the effect is profound. To begin, we’ll change the Index() method in HomeController:

    private ComicContext database = new ComicContext("ComicContextDb");
    public ActionResult Index()
    {
      var comics = database.ComicBooks.Select(book => book).OrderBy(book => book.Title);
      var model = comics.ToList();
      return View("IndexModel", model);
    }

The only change we made is the last line of the method, where instead of assigning the ‘comics’ list to the ViewBag, we pass it directly to the view as an argument in the View() method.

We’ve also specified that the view that should be called is named “IndexModel”, rather than the default “Index” that we used before. This is simply so we can have two alternative views for the same controller action. In a finished application, you’d probably choose one or the other and delete the other one.

You can use VS’s wizard to create this new view class. Right-click on the Index() method in the controller and select ‘Add view’. In the dialog, select ‘Create a strongly-typed view’ and give List<Book> as the model class.

Here’s the contents of IndexModel.cshtml:

@using ComicShop.Models
@model List<Book>

<h2>Comics</h2>

<ul>
    @foreach (var comic in @Model)
    {
        <li>
                @comic.Title: <b>@comic.Volume</b> (@comic.Issue)
        </li>
    }
</ul>

Note the two lines at the top. First, we have a ‘using’ statement which works the same as in regular C# code: we’re telling the view that we’ll be using classes in the ComicShop.Models namespace.

The second line is the key to creating a strongly-typed view. We specify that the model object is of type List<Book>. (This line will be inserted for you if you used the wizard to create the view as specified above.)

The foreach loop now loops over the elements in @Model rather than ViewBag.Model. If you type in the contents of the loop, now you’ll notice that IntellisenseĀ does work: you’ll get a list of properties of each comic object as you type.

The output of this page is the same as the earlier view. The only difference is how we’ve managed to interaction between the controller and the view. Besides enabling Intellisense, a strongly-typed view enables the compiler to check your code.

Or at least it should. In VS2012, if you type an incorrect name for a model property, an error is flagged in the editor (a squiggly red line appears under the incorrect name), but the project, somewhat confusingly, will still build. Of course when you try to run it, you’ll get an error page in the web browser.

You also need to be careful if you want to refactor your model class. For example, if you wanted to change the name of the Title property to something else like Header by using VS’s refactoring tool, it will change the property’s name in all the C# code, but not in the view code. Again, the error will be flagged up in the editor, but the project will still build (and of course, not run). Caution is required!

Advertisements
Post a comment or leave a trackback: Trackback URL.

Trackbacks

  • By MVC – common layouts « Programming tutorials on September 11, 2012 at 3:17 PM

    […] the simple example of a comic shop we’ve looked at so far, we’ve created a couple of very basic web pages using MVC 4 and […]

  • By MVC: unit tests « Programming tutorials on September 14, 2012 at 3:44 PM

    […] we’ll be testing code we’ve written in the original ComicShop project, the ComicShop.UnitTests project needs access to that code, which it doesn’t have at the […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: