Reputation: 8759
I'm working on an ASP.NET MVC 3 application that uses the Entity Framework and has a Class Library project with methods that return ObjectSet<T>
instances.
I've got a Controller that has code like this:
public ActionResult Index()
{
var students = context.GetStudents();
return View(students);
}
Here, GetStudents returns a type of System.Data.Objects.ObjectSet<Student>
.
In my view I have the code @Model.Count()
, which correctly displays the number of items in the model. This works wonderfully.
What's odd is that if I change the action so that it puts students
in ViewBag
then I start getting errors. Specifically, if I do:
public ActionResult Index()
{
var students = context.GetStudents();
ViewBag.Students = students;
return View(students);
}
And then add @ViewBag.Students.Count()
in my view I get a Yellow Screen of Death with the following message: "'System.Data.Objects.ObjectSet' does not contain a definition for 'Count'"
Why does it work (as expected) with the model but not with ViewBag
?
Upvotes: 0
Views: 1361
Reputation: 1039408
ViewBag uses new .NET 4.0 dynamic feature. Your code doesn't work for the exact same reason for which the following code doesn't work:
IEnumerable<int> array = new int[] { 1, 2, 3 };
dynamic foo = array;
Console.WriteLine(foo.Count());
Extension methods cannot be resolved on dynamic objects. You can make it work by the following monstrosity:
@(((System.Data.Objects.ObjectSet<Student>)Model).Count())
But please promise me you will never do anything like this.
The fact that your code doesn't work is actually a good thing. Because IMHO what you are trying to do is wrong in many aspects:
ObjectSet<T>
instead of using plain CLR objects.So the correct way to do this would be to define a view model which will contain only the properties that your view cares about. For example:
public class StudentViewModel
{
public string Name { get; set; }
}
and your controller action would query the repository and fetch a model which will be mapped to a view model passed to the corresponding strongly typed view:
public ActionResult Index()
{
var model = context.GetStudents();
var viewModel = model.Select(x => new StudentViewModel
{
Name = string.Format("{0} {1}", x.FirstName, x.LastName)
}).ToArray();
return View(viewModel);
}
and finally your strongly typed view would only depend on the specific view model (a view shouldn't care about data access specific stuff, it should only be passed whatever it needs to show):
@model StudentViewModel[]
<div>We have @Model.Length students</div>
Upvotes: 2