Friday, October 5, 2012

MVC View Compile Workarounds, or the SDK Strikes Back

I have resisted learning/using ASP.NET MVC for a while now, for several reasons. One, I'm a cranky old codger who doesn't like to change. Two, I don't hate the viewstate or the page life cycle, so when Microsoft proclaims that MVC will save us from those two pains, I go, "what pains?" Third, when I look at MVC code, I find myself grumbling, "If I wanted to be a PHP programmer, I would have stuck with that."

But time and upper management marches on, and recently I was pulled onto a project where the primary deliverable is an MVC 4 website. So I had to finally bite the bullet and get started. After installing the necessary components and add-ins and actually getting all the projects to load, I tried to build the solution, and got a compile error. The message was of the standard "The type or namespace name '...' does not exist in the namespace '...' (are you missing an assembly reference?)" variety; the breaking files, however, were entries like this:

c:\Users\nirvin\AppData\Local\Temp\
Temporary ASP.NET Files\temp\0260edc4\5834db2c\App_Code.q2tzfscm.0.cs

What? Why was Visual Studio generating code and then blaming me that it didn't build it right? Why should I care about the temporary ASP.NET files at this stage? I was trying to build, not run. I did some digging and found that Visual Studio attempts to compile the MVC views at build-time, instead of waiting until run-time (as standard ASP.NET does).

I consulted with my co-workers and determined that the issue was partially with my machine and partially with the solution. I could create an MVC 4 project from scratch and build it just fine, but this existing solution would fail consistently. However, other developers on the team were able to build the solution just fine on their machines. After more consultation and Googling, the following solutions were proposed:
  • Install Visual Studio 2012.
  • Uninstall MVC 2, 3, and 4 from my machine and then re-install them.

Neither of these options were appealing to me. I had not yet installed Visual Studio 2012 on my machine, and I knew that such a process would be time-consuming. The base install would take forever (after I found the right ISO that is), and then several of the critical add-ins and packages I use for daily development would have to be upgraded and reconfigured (e.g., ReSharper, dotCover, NuGet). Plus, I knew some of my teammates were using Visual Studio 2010 and building just fine, so I was somewhat skeptical of the proposed solution anyway.

The uninstall/re-install option, though, just rankled me. Ever since my my bad experience with Silverlight, SDK versions that refuse to play nice with one another (or, to put it another way, aren't properly isolated from one another) are a pet peeve of mine. Just as with the Visual Studio 2012 option, I didn't want to spend hours re-configuring my machine, and I certainly was not willing to play the install dependency guessing game.

After hours of trying to resolve the error, I finally found that you can actually turn off this "compile views" step.  While I didn't like this option, I needed to get back to actual work (particularly since my assigned tasks were all down in the data layer) so I decided to give this a shot. (I realize this might seem stupid; please keep reading, an endnote addresses the paradox here.) This particular setting is not accessible through Visual Studio 2010's UI, but can be toggled by editing the project file. Inside the project file there is a line that reads:

<MvcBuildViews>true</MvcBuildViews>

I switched it to "false", reloaded the project file, and built. Success! Well, not quite. I didn't want to check this change into source control; this was a personal choice/setting, and I didn't feel right imposing it on the rest of my team. It is, after all, a hack: telling the compiler to skip certain steps is not exactly advisable. I also didn't want to leave the project file checked out all the time; eventually I would accidentally check-in the hack, or have to make a legitimate change to the project file. Plus seeing stuff in the Pending Changes window at the end of the day just bothers me.

Now, the same variables/expressions that are available in pre- and post-build events are available in the project file markup and get evaluated at build-time. At first I looked into creating some rule/exception based on my machine name, but that variable wasn't readily available. So I hit on the idea of creating a separate build configuration instead.

I created a solution build configuration called "DevNoViewChecks" (emphasis on solution; the "Create new project configurations" option was not selected). This build configuration was copied from Debug, and so upon first creation it had each project set to "Debug". I then went to the MVC project, and created a new project build configuration for it with the same name (again with the emphasis; the "Create new solution configurations" option was not checked). This gave me a solution configuration "DevNoViewChecks" with each project set to "Debug", except for the MVC project, which was set to "DevNoViewChecks". I then went into the MVC project file, and edited the afore-mentioned line to read:

<MvcBuildViews Condition="'$(Configuration)' != 'DevNoViewChecks'">true</MvcBuildViews>

I then changed my build configuration in the Visual Studio toolbar to say "DevNoViewChecks", and built. No compile errors! Success! Actual Success!

I don't love that I had to hack this, and I'm not exactly warming to MVC here. But I do love that with this approach, no one has to think about it. I keep my solution set to "DevNoViewChecks", everyone else keeps themselves set to "Debug", and everyone's solution just works. No one has to care about what the other is doing and I don't have to think about what's going on with my project file all the time.

Someday I hope to actually resolve this issue with a deterministic approach that actually makes sense. But until then, this keeps me going.

(It is important to note that the website runs perfectly in the "DevNoViewChecks" build. There seems to be some inconsistency between how Visual Studio (attempts to) compile the views, and how the ASP.NET runtime actually compiles them. This compile error feels like a false negative.)

1 comment:

  1. UPDATE: Installing Visual Studio 2012 fixed the problem. That is, after I installed Visual Studio 2012 (which wasn't as arduous as previous VS installs have been), VS2010 decided it would build the solution in "Debug" mode. It can also be built with VS2012.

    ReplyDelete