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?
This discussion is about early vs late binding of objects and the inherent advantages of each scenario.
Early bound objects are known at compile time but must be a finite set. They will not produce runtime errors related to them not existing because they cannot be missing, however the set is finite and immutable.
Late bound objects are not known at compile time - they are instead known at runtime and can be a theoretically infinite set. Late bound objects usually represent the non-constants - things that change while your application runs. For example, a dependency injection framework like Unity or Ninject will late-bind from configuration file to allow you to inject virtually any object. If Unity or Ninject were to compile-time validate the injected objects, that would mean those objects were early bound and the framework would have to know about ALL possible types to ever be resolved... And if you introduced a new type, you'd need to recompile the framework to accept it!
In short, late binding offers flexibility to accommodate the unknown... such as your MVC Views, which are not known by Microsoft at the time that they release the framework.
The reason that MVC Views are late bound is that they are not a fixed set of things. Instead, they are bound from many sources (such as the file system and memory objects) at runtime, and each person's MVC project will have different views. If MVC were to validate the views at compile time, it would have to know the entire set of views before execution. The compiler will verify that the files exist (properly referenced in your project), but not that the files are properly referenced by the Controllers' ViewResults. The reason for THAT is that it empowers you to do a magnitude of things, including serve views/data dynamically. Not all Views come from disk... For example, nothing stops you from returning a FileResult from a MemoryStream of bytes. As another example, you could have the entire set of your views in the database and install a custom ViewEngine to render straight from database records.
The ViewResult also supports other types of data that aren't file based, like returning a binary sequence (image or file), XML, JSON, and others. JSON is often created from an object in memory at runtime, and so compile time validation would not be useful.
File I/O is also slow, and the Views are often cached in memory after initial load. If the application had to know WHAT it was caching in memory at compile time, the cache would not be very flexible or useful.
So ultimately no, there is no easy way to do this. You could write some unit tests that are not true to unit testing: they would execute each of your Controller ActionMethods and then call the ViewEngine to render the view and catch any file not found errors. That's about as close as you'll get without substantial effort.
You can precompile views in order to have errors in the Views become compile-time errors. By default, Views are JIT'd (Just in Time compiled) when your MVC app runs and first accesses them. If you modify the .csproj
file directly in Notepad or some other text editor you'll see <MvcBuildViews>
set to false
- just set it to true
but know that this will increase your compile time.