Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Msbuild pack doesn't choose the right version for ProjectReferences #6379

Closed
kabua opened this issue Jan 3, 2018 · 15 comments
Closed

Msbuild pack doesn't choose the right version for ProjectReferences #6379

kabua opened this issue Jan 3, 2018 · 15 comments

Comments

@kabua
Copy link

kabua commented Jan 3, 2018

Details about Problem

  • NuGet product used: VS2017
  • NuGet version (x.x.x.xxx): Package Manager Console Host Version 4.5.0.4685
  • VS version (if appropriate): 15.5.2
  • OS version (i.e. win10 v1607 (14393.321)): Version 10.0.16299 Build 16299
  • Worked before? If so, with which NuGet version: n/a

Steps to Reproduce

There are two solutions files, NugetProjectRefTest_Core and NugetProjectRefTest_Net, found respectively under the NugetProjectRefTest_Core and NugetProjectRefTest_Net folders.

  • Build both solutions.

Note: the zip file contains all source, binaries and nuget packages, so no real need to rebuild the solutions.

Back Ground

Each solution folder contains 2 DLLs and 1 console app.
The console app reference DLL1 as a project reference and DLL1 reference DLL2 also as a project reference. All 4 DLLs have a nuget version number of 8.0.0-Alpha001.

Expected Behavior

That both CoreDLL1 nuget packages, which depends on their respective CoreDLL2 package, reference the correct CoreDLL2 package version number.

Actual Behavior

  • Open the .\NugetProjectRefTest\NugetProjectRefTest_Core\CoreDll1\bin\Debug\CoreDll1.8.0.0-Alpha001.nupkg, the nuspec dependencies node looks like this:
       <dependencies>
            <group targetFramework=".NETCoreApp2.0">
                <dependency id="CoreDll2" version="8.0.0-Alpha001" exclude="Build,Analyzers" />
            </group>
        </dependencies>

Notice that the CoreDLL2 version is listed correctly as 8.0.0-Alpha001.

Now open the .\NugetProjectRefTest\NugetProjectRefTest_Net\Packages.Output\NetDll1.8.0.0-Alpha001-Debug.nupkg, the nuspec dependencies node looks like this:

        <dependencies>
            <group targetFramework=".NETFramework4.7.1">
                <dependency id="NetDll2" version="1.0.0" exclude="Build,Analyzers" />
            </group>
        </dependencies>

Notice that the CoreDLL2 version is not listed correct, its showing 1.0.0 but is should read: 8.0.0-Alpha001.

Sample Project

NugetProjectRefTest.zip

@zhili1208
Copy link
Contributor

@rohit21agrawal looks like pack didn't use assembly version but used default version here

@dasMulli
Copy link

dasMulli commented Jan 3, 2018

There is a Directory.Build.props containing conditions on $(Configuration), which may be unset this early in the build depending on how the project was invoked. AFAIK the restore task doesn't use the properties of the references from the sln metaproj so the version written to project.assets.json is the default version. Not sure how this is handled from inside VS.

@kabua
Copy link
Author

kabua commented Jan 4, 2018

I've tried using both the Version and the PackageVersion elements, neither one worked.

@kabua
Copy link
Author

kabua commented Jan 4, 2018

Last night while converting one of our projects from VS15 to VS17, I happened to notice that a depend nuget package was referencing a project reference dependency correctly. This morning I manually compared the working solution with one that wasn't working. I discovered that the working solution has one very minor difference. The working dependency project included a package called PropertyChanged.Fody.

Sure enough, as soon as I added PropertyChanged.Fody to the dependency project (e.g. A depends on B, and B is the project that now includes PropertyChanged.Fody.2.2.4) project A now sees the correct version of B.

Further investigation shows that it works just by adding the base package Fody2.3.15. The strange thing is, since there aren't any "weavers" Fody shouldn't do anything to the DLL but it is doing enough to force VS to pickup the correct version number.

Hope this helps.

@kabua
Copy link
Author

kabua commented Jan 4, 2018

Oh, there is one strange side effect to this. The nuget spec for A shows the debug (i.e. prerelease) version number of B regardless of which order I build things. E.g. building Debug then Release or Release and then debug produces the same result. Both A.8.0.0.nuget and A.8.0.0-Debug.nuget references B's 8.0.0-Debug package.

Batch file snippet:

msbuild "%solution%" /t:clean,build,pack /m /p:Configuration=Debug
if not [%ERRORLEVEL%] == [0] goto done

msbuild "%solution%" /t:clean,build,pack /m /p:Configuration=Release
if not [%ERRORLEVEL%] == [0] goto done

After thinking about this I actually like this "feature", that way my dependent's release nuget package A.nuget supports both the release and debug versions of the dependency package B. A very helpful feature.

Is this by design or is the an artifact of some kind?

@dasMulli
Copy link

dasMulli commented Jan 4, 2018

You also need to restore for the right version. the package versions are locked during restore.

=> msbuild /restore /t:Pack /p:Configuration=Release (/restore requires 15.5+)

See #4337

In your example, I feared that the restore won't see the values of PackageVersion to be set, since if you don't specify /p:Configuration=..., it won't trigger the '$(Configuration) == 'Debug' property group. (The default is specified in the csproj itself), so it really only depends on how the project was restored.

@kabua
Copy link
Author

kabua commented Jan 4, 2018

@dasMulli I tried your idea of adding restore first, i.e.

msbuild "%solution%" /restore /t:clean,build,pack /m /p:Configuration=Debug
if not [%ERRORLEVEL%] == [0] goto done

and

msbuild "%solution%" /t:restore,clean,build,pack /m /p:Configuration=Debug
if not [%ERRORLEVEL%] == [0] goto done

Either of them worked.

However, I just tried another idea, I realized that the dependency projects that are having issues don't include any nuget package references. So, it isn't the fact that I added Fody it's that I added at least one package - any package will do.

IOWs, the nuget logic only works if the dependency project has a reference to at least one nuget package. If the dependency project doesn't include any nuget packages then nuget isn't reading the dependency project's version number correctly. Very strange indeed.

Hope this helps.

@kabua
Copy link
Author

kabua commented Jan 4, 2018

FYI - as a work-a-round I created an empty nuget package as a place holder, like so:

<?xml version="1.0"?>
<package >
    <metadata>
        <id>Required.PlaceHolder</id>
        <version>1.0.0</version>
        <title>Required PlaceHolder</title>
        <authors>Tristen Fielding</authors>
        <owners>Tristen Fielding</owners>
        <iconUrl>https://s20.postimg.org/5ko01nwl9/icons8-feed-in-40.png</iconUrl>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>At the moment nuget required all project references to include at least one package. Thus this empty package fills that requirement.</description>
        <releaseNotes></releaseNotes>
        <copyright>Copyright 2017</copyright>
	<contentFiles>
		<files include="readme.txt" />
	</contentFiles>
    </metadata>
</package>

Where the readme.txt has the same text same as the description.

This works nicely, it doesn't add anything to the project's output etc but it does cause VS and/or nuget to work correctly.

@dasMulli
Copy link

dasMulli commented Jan 4, 2018

Ah I see where this is going.

As long as there is no package reference, you'll need to set the property

<RestoreProjectStyle>PackageReference</RestoreProjectStyle>

in classic csproj files.

@zhili1208 @rohit21agrawal is just adding an import for the sdk target to a classic project even "supported"?

@dasMulli
Copy link

dasMulli commented Jan 4, 2018

@kabua for .NET Framework packages, if you want msbuild-integrated package generation, you will have a better experience using an "sdk-based" project since it sets or defaults all the required properties. You can create a .NET Standard class library and change the TargetFramework property in the csproj file from netstandard2.0 to e.g. net461. Depends on what you need - "logic"-libraries should be fine.

@rohit21agrawal
Copy link
Contributor

rohit21agrawal commented Jan 4, 2018

@dasMulli i am afraid it's not. You can either be a packages.config based classic style project, or you can be PackageReference based classic style project, or you can be a NETCore SDK style project .

@kabua - @dasMulli is right, you do need RestoreProjectStyle property for what you are doing.

@kabua
Copy link
Author

kabua commented Jan 4, 2018

@dasMulli thanks, adding PackageReference worked!

I will also try changing my projects to .NET Standard (which I haven't done before so I'm not sure what I'm getting myself into). We have 12 projects that make up two frameworks that are consumed by several WPF and ASP.NET WebAPI applications. Therefore, can WPF and ASP.NET applications consume .NET Standard libraries?

Thanks for the quick responses and help on this.

@dasMulli
Copy link

dasMulli commented Jan 4, 2018

Yes those projects can consume .NET Standard libraries.

If you need .NET Framework specific functionality in the library packages (e.g. WPF-specific libraries, System.Web namespace) you can still use the new project format and tooling to produce .NET Framework specific packages - there's just no template for this in visual studio, but quite a few open source projects have moved to using this.

There's a community slack channel if you need some more help with that (signup at https://tattoocoder.com/aspnet-slack-sign-up/, I have the same username there).

@red8888
Copy link

red8888 commented Mar 14, 2019

how can you set the version from command line? I do this with nuget pack now:
nuget.exe pack myapp.csproj -IncludeReferencedProjects -Properties Configuration=Release;prerelease=INeedToSetThisFromTheCommandNotStaticConfigFile-123

@nkolev92
Copy link
Member

nkolev92 commented Nov 7, 2020

Sounds like the original problem has been long solved.

@red8888 You can refer to https://docs.microsoft.com/en-us/nuget/create-packages/creating-a-package-dotnet-cli for that

@nkolev92 nkolev92 closed this as completed Nov 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants