502502
502502

Reputation: 437

ASP.NET MVC3 ViewModel - Confused

I'm learning about ViewModels in C# ASP.NET MVC 3, and I'm stuck at displaying data from the ViewModel in my View.

The Models:

public class Author
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Book> Books { get; set; }
}

public class Book
{
    public int Id { get; set; }
    public int AuthorId { get; set; }
    public string Title { get; set; }
    public decimal Price { get; set; }
}

In my Index View I want to show general lists of both Authors and Books. I have made a ViewModel for this:

public class BookIndexViewModel
{
    public List<Book> Books { get; set; }
    public List<Author> Authors { get; set; }
}

Here is my Index() action method from the controller:

public ViewResult Index()
    {
        BookIndexViewModel viewModel = new BookIndexViewModel();
        viewModel.Authors = db.Authors.ToList();

        // leaving Books empty for now

        return View(viewModel);        
    }

I have a strongly typed Index View where I want to show the list of Authors:

@model IEnumerable<NewBookStore.ViewModels.BookIndexViewModel>

@foreach (var author in Model.Authors) {
<tr>
    <td>
        @author.Name
    </td>
</tr> 
}

It's the Model.Authors part that doesn't work. When I type Model. and wait for IntelliSense to show Authors, it isn't listed. The error description is:

'System.Collections.Generic.IEnumerable' does not contain a definition for 'Authors' and no extension method 'Authors' accepting a first argument of type 'System.Collections.Generic.IEnumerable' could be found (are you missing a using directive or an assembly reference?)

Upvotes: 2

Views: 2863

Answers (6)

TConere
TConere

Reputation: 61

[Note - I don't have enough exp to make this a comment rather than an answer!]

I was reading another article regarding ViewModels and from what @Darin Dimitrov was saying is that you should avoid putting Domain objects into your ViewModel,

"View models should not reference any services. View models should not reference any domain models."

see -> ASP.NET MVC 3 Viewmodel Pattern

I know patterns are more like guides that don't fit every scenario but like the OP, I need to display a list of domain objects (books and authors we'll just say) so in the OP's example, should the ViewModel have?:

public class BookIndexViewModel
{
   public IEnumerable<SelectListItem> Books { get; set; }
   public IEnumerable<SelectListItem> Authors { get; set; }       
}    

The BookIndexViewModel is then populated in your controller (which might use a service to get a list of Book and a list of Author to flatten into ViewModel) ??

I too am learning this stuff so open to suggestions/comments and corrections!! Thanks.

Upvotes: 0

EagleHail
EagleHail

Reputation: 136

Use this instead

@model NewBookStore.ViewModels.BookIndexViewModel

Upvotes: 0

keshav
keshav

Reputation: 876

the model in the view shouldnt be IEnumerable. You are sending a single model which has 2 lists in it. You are not sending a list of viewmodels.

Upvotes: 2

jim tollan
jim tollan

Reputation: 22485

Finnayra,

Your error here is that you aren't defining the model correctly. Your model already holds the IEnumerable<> collections, so no need to make it Enumerable as well. Try:

@model NewBookStore.ViewModels.BookIndexViewModel

Upvotes: 0

Shyju
Shyju

Reputation: 218722

Because you are not passing a collection your View, You are passing only one object of BookIndexViewModel class from your action method.

To fix this, update your view to to bind it to only one instance instead of a collection

@model NewBookStore.ViewModels.BookIndexViewModel

@foreach (var author in Model.Authors)
{
<tr>
    <td>
        @author.Name
    </td>
</tr> 
}

Upvotes: 0

Dean Ward
Dean Ward

Reputation: 4783

@model IEnumerable<NewBookStore.ViewModels.BookIndexViewModel> should be @model BookIndexViewModel instead!

You don't want an IEnumerable of BookIndexViewModel - the Authors property is directly off your BookIndexViewModel.

Cheers, Dean

Upvotes: 0

Related Questions