17

Resolved

NuGet broke my MVC build & deploy

description

MVC v5.1 was recently GAC'd (see KB 2994397). When doing File -> New Project for ASP.NET, the project templates set MVC CopyLocal to true. For example (original MVC 5 tooling):
<Reference Include="System.Web.Mvc, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
    <Private>True</Private>
    <HintPath>..\..\packages\Microsoft.AspNet.Mvc.5.0.0\lib\net45\System.Web.Mvc.dll</HintPath>
</Reference>
We used NuGet to update package to v 5.1. At that time, it removed the CopyLocal/Private setting:
<Reference Include="System.Web.Mvc, Version=5.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll</HintPath>
</Reference>
(Note that it also added SpecificVersion=false, which seems odd given that NuGet's packages.config is designed to reference specific versions.)

As a result, when MVC 5.1 was GAC'd as part of MS14-059, our application stopped deploying correctly to machines without this update installed. (There were also some other problems that occurred because CopyLocal=true was dropped, such as Razor compilation failing on our dev boxes.)

Can NuGet be changed not to drop CopyLocal settings in references? Or, perhaps NuGet should always set CopyLocal/Private=true on all references it adds (and probably do the same for SpecificVersion as well).

Here's an example of this problem affecting our users:
http://stackoverflow.com/questions/26396489/system-web-mvc-not-functioning-as-expected-after-windows-update

It also affected our project's build. If NuGet had kept CopyLocal, we would have kept working when the Windows Update came out, thanks to the original MVC template settings. But since NuGet removed that setting, we broke when the Windows Update came out.

Note that the precise steps above now behave differently on my machine. Because the assembly is GAC'd, if I install/update now, it sets CopyLocal/Private to true. But if I then upgrade to an assembly that isn't currently GAC'd (such as from MVC v5.1 to MVC v5.2), it again drops the CopyLocal/Private=true setting. So if MVC 5.2 is ever GAC'd, this problem will occur again.

comments

Togakangaroo wrote Oct 17, 2014 at 1:54 AM

JeffHandley wrote Oct 17, 2014 at 4:09 AM

NuGet is not responsible for the CopyLocal setting in either direction. Visual Studio's project systems control that when NuGet calls into the project system to add the reference. My guess is that the project system expects that if you are referencing an assembly that is in the GAC (and for a strong name, the GAC always wins), then that assembly will also be in the GAC on the target machine.

We'll talk with some folks to see what can be done here though.

Togakangaroo wrote Oct 17, 2014 at 5:10 AM

What needs to happen is <private>True</private> just needs to be added to the project file. I find the whole copy local setting to be really unreliable.

davidmatson wrote Oct 17, 2014 at 4:58 PM

NuGet is not responsible for the CopyLocal setting in either direction. Visual Studio's project systems control that when NuGet calls into the project system to add the reference.
I understand where you're coming from, and I agree you're not intending to reset the CopyLocal flag. However, I respectfully disagree. NuGet is ultimately responsible for the APIs it calls.
Officer: You were speeding on the way down that hill.
Driver: I was not responsible for my speed; the cruise control handles that detail when I turn it on.
:)

As a package manager, the NuGet update package command is more than just a generic add reference gesture; it also handles things like binding redirects to make a specific version work correctly. (NuGet isn't just a VS remove/add reference wrapper; how it uses the VS APIs is a NuGet implementation detail.) Given this NuGet bug, it sounds like NuGet would need to use a different implementation strategy (perhaps different/more VS APIs) to meet the needs of update package in these cases.

In theory, NuGet could be blocked from fixing this bug due to a current VS technical limitation, though though I hope (and suspect) that's not the case. I'm hoping there's a different, perhaps lower-level, implementation choice that would resolve this bug.

davidmatson wrote Oct 17, 2014 at 4:59 PM

We'll talk with some folks to see what can be done here though.
Wonderful. Thanks for looking into this!

davidmatson wrote Oct 17, 2014 at 5:04 PM

It sounds like it's all related to this:
http://blogs.msdn.com/b/webdev/archive/2014/10/16/microsoft-asp-net-mvc-security-update-broke-my-build.aspx
Kind of. The current text there doesn't really address the specific problem I hit with MVC 5. And this kind of problem can occur in other situations as well (any time a NuGet package assembly is GAC'd on a dev machine).

davidmatson wrote Oct 17, 2014 at 5:26 PM

davidmatson wrote Oct 18, 2014 at 12:05 AM

BTW, simply setting the property to true isn't enough. In that case, VS will only persist it if it's different from the default. To force VS to persist, setting it to false first appears to do the trick:
            VSProject vsProject = (VSProject)(project.Object);
            References2 references = (References2)vsProject.References;
            Reference5 reference = (Reference5)references.Add(@"<path>\System.Web.Mvc.dll");
            reference.SpecificVersion = true;
            reference.CopyLocal = false;
            reference.CopyLocal = true;

dannytuppeny wrote Oct 20, 2014 at 12:33 PM

Today it was reported to me that all of our local QA apps were broken. It seems like we may have been bitten by this (we upgraded MVC via NuGet).

Luckily, our QA servers were patched and we noticed this; if our production servers had been patched, this would've taken our live apps out for whoever long it took us to figure this out and get a new version tested/staged/deployed.

Whether this is an MVC/WindowsUpdate or NuGet issue; someone needs to take responsibility for ensuring something is put in place to stop this happening again. If Microsoft starts breaking production apps with Windows Updates (which are typically done by ops teams, and shouldn't need dev teams to fix the resulting issues) it'll reduce the frequency at which they install Windows updates (or worse, they'll just have a bad impression of your platform and migrate away).