使用ViewBag时,在Razor语法中缺少命名空间或程序集,但在Model中很好

时间:2011-06-14 17:17:23

标签: asp.net-mvc-3

我正在使用一个使用Entity Framework的ASP.NET MVC 3应用程序,并且有一个类库项目,其中包含返回ObjectSet<T>个实例的方法。

我有一个控制器,其代码如下:

public ActionResult Index()
{
    var students = context.GetStudents();

    return View(students);
}

此处,GetStudents返回System.Data.Objects.ObjectSet<Student>类型。

在我看来,我有代码@Model.Count(),它正确显示模型中的项目数。这很有效。

奇怪的是,如果我更改操作以便将students放入ViewBag,那么我就会开始出错。具体来说,如果我这样做:

public ActionResult Index()
{
    var students = context.GetStudents();

    ViewBag.Students = students;

    return View(students);
}

然后在我的视图中添加@ViewBag.Students.Count()我得到一个黄色死亡屏幕,并显示以下消息:“'System.Data.Objects.ObjectSet'不包含'Count'的定义”

为什么它与模型一起工作(如预期),而不是ViewBag

1 个答案:

答案 0 :(得分:2)

ViewBag使用新的.NET 4.0动态功能。您的代码不能用于以下代码不起作用的完全相同的原因:

IEnumerable<int> array = new int[] { 1, 2, 3 };
dynamic foo = array;
Console.WriteLine(foo.Count());

无法在动态对象上解析扩展方法。您可以通过以下怪物使其工作:

 @(((System.Data.Objects.ObjectSet<Student>)Model).Count())

但请保证我永远不会做这样的事情。

您的代码不起作用的事实实际上是一件好事。因为恕我直言你想要做的事情在很多方面都是错误的:

  1. 您正在将域模型传递给视图,而不是使用视图模型。
  2. 您正在将数据访问特定对象传递给您的视图,例如ObjectSet<T>而不是使用普通CLR对象。
  3. 您正在使用弱类型的ViewBag =&gt;你正在失去Intellisense,你需要在你的视图中执行一些强制转换以调用某些辅助方法的某些重载(这会导致意大利面条代码),由于ViewBag的动态特性,你会得到一些神秘的错误,你可以命名它,...
  4. 因此,正确的方法是定义一个视图模型,该模型仅包含视图所关注的属性。例如:

    public class StudentViewModel
    {
        public string Name { get; set; }
    }
    

    并且您的控制器操作将查询存储库并获取将映射到传递给相应强类型视图的视图模型的模型:

    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);
    }
    

    最后你的强类型视图将仅依赖于特定的视图模型(视图不应该关心数据访问特定的东西,它应该只传递它需要显示的任何东西):

    @model StudentViewModel[]
    <div>We have @Model.Length students</div>