dotnet / msbuild

The Microsoft Build Engine (MSBuild) is the build platform for .NET and Visual Studio.
https://docs.microsoft.com/visualstudio/msbuild/msbuild
MIT License
5.21k stars 1.35k forks source link

dotnet build doesn't resolve package references correctly for old style projects #5250

Open TFTomSun opened 4 years ago

TFTomSun commented 4 years ago

Steps to reproduce

Dotnet build does not resolve package references in old style projects, but restore seems to be done fine. I tried also several variations like dotnet msbuild /t:restore;build etc. All lead to the same build errors.

PackageReferenceBugDemo.zip

Project file

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" 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>
    <ProjectGuid>{C27219F1-6C86-4D9C-B9C3-4B01B5D9879B}</ProjectGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>PackageReferenceBugDemo</RootNamespace>
    <AssemblyName>PackageReferenceBugDemo</AssemblyName>
    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <Deterministic>true</Deterministic>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Nunit" Version="2.5.10.11092"/>

    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Class1.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <ItemGroup>

  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Directory contents:

see attachment

Command line

dotnet build

Expected behavior

The build runs fine

Actual behavior

The nunit package reference doesn't get resolved

Environment data

dotnet msbuild //version

Microsoft (R)-Build-Engine, Version 16.4.0+e901037fe f▒r .NET Core
Copyright (C) Microsoft Corporation. Alle Rechte vorbehalten.
rainersigwald commented 4 years ago

The targets that resolve package assets at build time are part of the .NET Core SDK, and so aren't imported in this project. We don't currently support building non-SDK projects with the .NET Core CLI, so this is behaving as expected.

Do you have a scenario where this support would be important to you? I don't think it's super likely to make it to the top of the priority list but new data could help.

TFTomSun commented 4 years ago

@rainersigwald in our big organization we have a mixture of old style and new style projects. The dotnet cli and it's global tools is an easy to use approach for defining pipelines. I wish I could build a solution that contains both types of projects with it. Restructuring all projects in a big organization at one time is not realistic, so a transition path from the old world to the new world would be really helpful.

rainersigwald commented 4 years ago

I wish I could build a solution that contains both types of projects with it.

You can, but you have to use MSBuild.exe (from VS or VS build tools).

TFTomSun commented 4 years ago

Is msbuild.exe available as a global tool, so that i can pull it via Artifactory in our intranet? Does it work on Linux as well? Are docker images with msbuild.exe available? The problem with most tools in dev ops scenarios is that it's complicated to deploy and start them, especially within enterprise networks. With the dotnet cli it's easy. That's why i like it. I wish we would have one build environment that works simple like that in every environment for all type of projects, so that we can build state of the art dev ops solutions even if we still have legacy code to support.

lextm commented 4 years ago

Is msbuild.exe available as a global tool, so that i can pull it via Artifactory in our intranet? Does it work on Linux as well?

No global tool. For Windows, install Visual Studio (Build Tools only, or other editions). For Linux, you might install Mono which ships MSBuild.

If you are working on a non-SDK style project, you are supposed to be on Windows. So if you face the same challenge on Linux, you probably should review carefully whether that's the trouble you want to afford.

Are docker images with msbuild.exe available?

It depends on which images you are talking about. If there is none, you can build your own.

I wish we would have one build environment that works simple like that in every environment for all type of projects

You can recommend that on the right repo https://github.com/dotnet/sdk/issues.

TFTomSun commented 4 years ago

I can already build full framework projects (SDK style) on Linux by referencing Microsoft.NETFramework.ReferenceAssemblies. I can use the Dotnet Core SDK Docker images that are provided by Microsoft for that. I can also install the Dotnet SDK on a Windows machine, the CI/CD scripts stay the same like on Linux.

Just because of the Old style Format, I can't use all this tooling and need to setup a complete different build environment and write different CI/CD scripts which are even platform dependent. I just wonder why. I thought the SDK style is just another format for a project file.

lextm commented 4 years ago

@TFTomSun The SDK style project format is more an indicator of scope.

All .NET 5 applications will be buildable with the .NET CLI, ensuring that you have common command-line tooling across projects.

You can find the above statement from .NET 5 Roadmap, so the unification you wanted is coming.

However you wanted, non SDK style projects (most likely to be WCF/WF, ASP.NET 2.x/4.x) seem to be out of scope.

rainersigwald commented 4 years ago

"SDK style" is indeed "another format for a project file". It's just a fancy way to import some stuff that has a bunch of defaults (like "compile **/*.cs).

However, the .NET Core SDK does not contain all of the build logic and SDKs that are available in Visual Studio. It's designed around .NET Core scenarios. It doesn't support C++, and it doesn't support projects that use other Visual Studio features. As a result, to build those projects, you must continue to use Visual Studio (or Visual Studio Build Tools).

TFTomSun commented 4 years ago

@rainersigwald That's why I wonder. The projects I tried to build don't use any features that couldn't be built by a similar SDK style project format with for example TargetFramework net48. They don't contain WCF, WF, ASP.NET 2/4.

That means, technically everything is in place to built these kind of projects with the dotnet sdk. Just because they have the old style format, they can't be built via dotnet build. A possibility to develop dotnet sdk based CI/CD solutions that work with legacy code as well, would be nice, even if dotnet build would fallback to an installed build tools instance.

But I understand now, that the suggested migration path is to upgrade to sdk style first before you can use the dotnet cli for building the projects, it's just difficult to achieve that in large code bases.

nkosi23 commented 2 years ago

I can confirm that this limitation is super counter-intuitive. Especially in light of the Microsoft.NETFramework.ReferenceAssemblies nuget package. All the build works, but we will have to migrate the whole project style just because PackageReference is not resolved at build-time. This is not about providing support for C++, this looks more like something you have overlooked and that should be fixed. This looks like a low hanging fruit.

As far as the use case, we have been migrating to .NET Core progressively. We started by converting our projects to use the PackageReference format (which has been supported by classical projects for a little while now). We wanted to transition to using the new .NET SDK (dotnet cli etc..) without disrupting our current projects. Proper resolving of PackageReference would have allowed us to migrate our projects one after the other calmly and safely, instead of creating a big bang and postponing the migration until we have time to handle this massive undertaking (we develop under linux so we do not have access to the migration facilities of Visual Studio).

bz-wow commented 2 years ago

Very bad experience that .net framwork project is not supported... Wasting lots of time on such issue

bz-wow commented 2 years ago

I wish I could build a solution that contains both types of projects with it.

You can, but you have to use MSBuild.exe (from VS or VS build tools).

Use msbuild directly, it shows error "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets(1 98,5): error : Your project file doesn't list 'win' as a "RuntimeIdentifier". You should add 'win' to the "RuntimeIdent ifiers" property in your project file and then re-run NuGet restore." PS: this should be a nuget.exe bug according to https://github.com/NuGet/Home/issues/10590. Earlier nuget version like 5.4.0 is ok.

Not sure if any other issue appears if above one is fixed.

Had to run nuget (like v5.4, latest version has bug mentioned avove) restore and then msbuild to make it built.

Additionally, this limition and solution are not mentioned in official doc - https://docs.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files