msbuild: PackageReference is not resolved while it works in Visual Studio

Steps to reproduce

  • Create a Empty Web Application Project in Visual Studio.
  • Make it really empty by removing the DotNetCompilerPlatform stuff
  • Add a Nuget package reference to Microsoft.AspNet.Mvc version 5.2.4
  • Add a Global.asax and its code behind with a using System.Web.Mvc
  • Compile in Visual Studio
  • Compile from the command line

Directory contents:

/
- Properties/
  - AssemblyInfo.cs
- Global.asax
- Global.asax.cs
- web.config
- Empty.WebHost.csproj

Empty.WebHost.csproj:

<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>
    </ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{080CBD85-3B74-4ECC-8389-47E594F376DE}</ProjectGuid>
    <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>Empty.WebHost</RootNamespace>
    <AssemblyName>Empty.WebHost</AssemblyName>
    <TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
    <UseIISExpress>true</UseIISExpress>
    <Use64BitIISExpress />
    <IISExpressSSLPort />
    <IISExpressAnonymousAuthentication />
    <IISExpressWindowsAuthentication />
    <IISExpressUseClassicPipelineMode />
    <UseGlobalApplicationHostFile />
    <NuGetPackageImportStamp>
    </NuGetPackageImportStamp>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Web.DynamicData" />
    <Reference Include="System.Web.Entity" />
    <Reference Include="System.Web.ApplicationServices" />
    <Reference Include="System.ComponentModel.DataAnnotations" />
    <Reference Include="System" />
    <Reference Include="System.Data" />
    <Reference Include="System.Core" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="System.Web.Extensions" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Drawing" />
    <Reference Include="System.Web" />
    <Reference Include="System.Xml" />
    <Reference Include="System.Configuration" />
    <Reference Include="System.Web.Services" />
    <Reference Include="System.EnterpriseServices" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.4" />
  </ItemGroup>
  <ItemGroup>
    <Content Include="Web.config" />
    <Content Include="Global.asax" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Properties\AssemblyInfo.cs" />
    <Compile Include="Global.asax.cs">
      <DependentUpon>Global.asax</DependentUpon>
    </Compile>
  </ItemGroup>
  <PropertyGroup>
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
  </PropertyGroup>
  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
  <Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
  <ProjectExtensions>
    <VisualStudio>
      <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
        <WebProjectProperties>
          <UseIIS>True</UseIIS>
          <AutoAssignPort>True</AutoAssignPort>
          <DevelopmentServerPort>1983</DevelopmentServerPort>
          <DevelopmentServerVPath>/</DevelopmentServerVPath>
          <IISUrl>http://localhost:1983/</IISUrl>
          <NTLMAuthentication>False</NTLMAuthentication>
          <UseCustomServer>False</UseCustomServer>
          <CustomServerUrl>
          </CustomServerUrl>
          <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
        </WebProjectProperties>
      </FlavorProperties>
    </VisualStudio>
  </ProjectExtensions>
</Project>

Global.asax:

<%@ Application Codebehind="Global.asax.cs" Inherits="Empty.Web" Language="C#" %>

Global.asax.cs:

using System.Web;
using System.Web.Mvc;

namespace Empty.Web
{
  public class MvcApplication : HttpApplication
  {
    protected void Application_Start()
    {
      AreaRegistration.RegisterAllAreas();
    }
  }
}

web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
</configuration>

Properties\AssemblyInfo.cs:

using System.Reflection;

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Command line

msbuild .\Empty.WebHost.csproj /t:restore,Build

Expected behavior

The build should succeed in Visual Studio. The build should succeed on the command line.

Actual behavior

The build succeeds in Visual Studio. The build fails on the command line.

Build FAILED.

"P:\cy\apps\cam\src\Core\Empty.WebHost\Empty.WebHost.csproj" (restore;Build target) (1) ->
(CoreCompile target) ->
  Global.asax.cs(2,18): error CS0234: The type or namespace name 'Mvc' does not exist in the namespace 'System.Web' (are you missing an assembly reference?) [ P:\cy\apps\cam\src\Core\Empty.WebHost\Empty.WebHost.csproj]

    0 Warning(s)
    1 Error(s)

Environment data

msbuild /version output:

Microsoft (R) Build Engine version 15.5.180.51428 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

15.5.180.51428

OS info: Windows 10 Visual Studio 2017 15.5.6

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 19 (6 by maintainers)

Commits related to this issue

Most upvoted comments

/t:Restore;Build does not work reliably. Instead, specify msbuild.exe /restore, which runs the restore operation in a separate phase and ensures that the build operates with the latest restored build logic.

Adding a separate project that uses <MSBuild with Targets="Restore;Build" will also not be reliable.

Running nuget.exe within MSBuild also will not work.

The core problems with all of these approaches are the same: MSBuild tries very hard to avoid loading projects more than it needs to. That means that if you modify the project (or create new imports, such as by restoring NuGet packages) after the project has already started building, the rest of that build will not see the updated build logic, because it’s already read from disk.

The /restore command-line argument fixes this by doing the /t:Restore in a separate phase, allowing the rest of the build (as specified on the command line) to pick up the latest logic.

In my case the root cause of this issue was old Nuget.exe version. Old version used old MsBuild v14 instead on v15 and it causes build issues after nuget restore. Try to update it with nuget.exe update -self

Or try to change ToolsVersion="12.0" to ToolsVersion="15.0" in csproj files

Perhaps having an additional argument to the <MSBuild would be the solution to perform this restore?

That’s tracked by #2811, but to set expectations it’s definitely very hard and possibly too hard, which is why it isn’t done already.

Is it possible for you to have a Restore target in the file that defines BuildTIMSNET that does something like

<Target Name="Restore">
    <MSBuild
      Projects="@(ProjectsToBuild)"
      Properties="PostBuildEvent="
      Targets="Restore"
      BuildInParallel="true"
      />
</Target>

?

Also, msbuild.exe /restore runs Restore and then the default target. If you want to do the exec-MSBuild approach for a subtree, you should call msbuild.exe /t:Restore to run just the restore operation and do the build with the MSBuild task.