2

I see a lot of posts about strongly typing the View's model data.

I am interested in somehow strongly typing the View itself.

It concerns me that a controller action returning View(xyz) could crash at run-time, if the view's model type changes, or the name / location of the view itself changes. In my opinion, the loose coupling of the MVC framework goes too far in this specific area, becoming counterproductive in a RAD environment. (not getting immediately notification of breaking changes)

Is there a way to trigger compile-time errors if View() calls are invalid due to missing .cshtml files or unmappable model types?

4

2 回答 2

5

这个讨论是关于对象的早期绑定和晚期绑定以及每个场景的固有优势。

早期绑定对象在编译时是已知的,但必须是有限集。它们不会产生与它们不存在相关的运行时错误,因为它们不能丢失,但是该集合是有限且不可变的。

后期绑定对象在编译时是未知的——它们在运行时是已知的,并且可以是理论上的无限集。后期绑定对象通常代表非常数——在应用程序运行时发生变化的事物。例如,像 Unity 或 Ninject 这样的依赖注入框架将从配置文件后期绑定,以允许您注入几乎任何对象。如果 Unity 或 Ninject 要在编译时验证注入的对象,那将意味着这些对象是早期绑定的,并且框架必须知道所有可能要解析的类型......如果你引入了一个新类型,你' d 需要重新编译框架才能接受!

简而言之,后期绑定提供了适应未知事物的灵活性……例如您的 MVC 视图,微软在发布框架时并不知道这些视图。

MVC 视图延迟绑定的原因是它们不是一组固定的东西。相反,它们在运行时从许多来源(例如文件系统和内存对象)绑定,每个人的 MVC 项目会有不同的视图。如果 MVC 要在编译时验证视图,它必须在执行之前知道整个视图集。编译器将验证文件是否存在(在您的项目中正确引用),但不是控制器的 ViewResults 正确引用了文件。这样做的原因是它使您能够做很多事情,包括动态地提供视图/数据。并非所有视图都来自磁盘...例如,没有什么能阻止您从 MemoryStream 字节返回 FileResult。作为另一个示例,您可以在数据库中拥有整个视图集,并安装自定义 ViewEngine 以直接从数据库记录中呈现。

ViewResult 还支持其他不基于文件的数据类型,例如返回二进制序列(图像或文件)、XML、JSON 等。JSON 通常是在运行时从内存中的对象创建的,因此编译时验证不会有用。

文件 I/O 也很慢,并且视图通常在初始加载后缓存在内存中。如果应用程序必须在编译时知道它在内存中缓存了什么,那么缓存就不会非常灵活或有用。

所以最终不,没有简单的方法可以做到这一点。您可以编写一些不适用于单元测试的单元测试:它们将执行您的每个控制器 ActionMethods,然后调用 ViewEngine 来呈现视图并捕获任何未找到文件的错误。这与您无需付出大量努力即可获得的结果差不多。

可以预编译视图以使视图中的错误成为编译时错误。默认情况下,当您的 MVC 应用程序运行并首次访问它们时,视图是 JIT(即时编译)的。如果您.csproj直接在记事本或其他文本编辑器中修改文件,您会看到<MvcBuildViews>设置为false- 只需将其设置为true但知道这会增加您的编译时间。

于 2013-11-11T04:26:38.097 回答
0

如果您有以下模型:

public class MyModel
{
    public int MyInt = 0;
}

但是您的视图执行以下操作:

@this.Model.MyOtherProperty

这将产生编译时错误(查看页面时)。如果视图试图访问不存在的属性,则会发生错误。

于 2013-11-11T04:24:31.433 回答