简体   繁体   中英

How should I publish my projects as NuGet packages considering dependencies between them?

The problem:

I have a toolkit consisting of many packages, the source is just one big solution containing the package sources, unit tests and demos.

Each package project needs to be a separate NuGet package, but some projects depend on other projects.

In projects, I have local project dependencies, pointing to the project files.

Lets say I have a root package A . B , C , and D depends on A . And let's say E depends on B .

Let's say the dependency tree looks like this:

- A
  |-B-E
  |-C
  |-D

What will happen when I publish packages A , B , C , D , E ?

Will package E be just project E compiled with the dependency on packages B (where B depending on package A ) - or the package E would have no dependencies and A and B projects built in?

Please note the difference between project reference and package reference !

In my solution, I have only project references. What I want in my resulting packages are package references. My B.csproj should depend on A.csproj but my B.nupkg should depend on A.nupkg .

What I want to achieve is being able to upgrade individual packages without breaking the rest of them. Of course I mean non-breaking changes, like adding a class or method to A, fixing a bug in A without changing the API.

Let's say I find a bug in package A affecting all the other packages. I want just fix the package A and publish it as a new version. Then, the project X using package B should also receive the fix, because it would use the latest version of A dependency.

Is it possible and what should I do to achieve such behavior?

I tested a several ways that (kind of) worked. First I just first published the dependencies, then added NuGet package dependencies to the projects that used them. I mean the projects that were published later as packages. That worked, however it was awfully tedious to debug. A kind of a nightmare in fact.

Then I tested another approach - 2 kind of references varying between the Debug and Release configurations. The Debug configuration had the references to the projects, the Release configuration had the references to the packages. This is actually pretty manageable, however, the project files are pretty messy, it's all pretty complicated and still tedious to maintain.

I've read somewhere, that the .NET and NuGet will somehow solve it itself. I find it hard to believe. Is it THAT smart? Just leave normal configuration, references to the projects, and the packages will reference the corresponding packages if available?

Can anybody confirm or deny that?

There's a way to find out, publish the packages. But it's not exactly fully reversible. What goes to NuGet stays there forever. I can unlist those versions, but still it would take a lot of time to test it and it would create a mess.

Maybe somebody already tested this, or found some solid information about it.

I've read somewhere, that the .NET and NuGet will somehow solve it itself. I find it hard to believe. Is it THAT smart? Just leave normal configuration, references to the projects, and the packages will reference the corresponding packages if available?

When you pack a project, NuGet will turn ProjectReferences into package dependencies, just the same way as PackageReferences become package dependencies. There's nothing smart, in fact it's incredibly simple. Therefore, there's no need to switch based on debug vs release, or anything else. It's super easy to validate yourself:

dotnet new sln
dotnet new classlib -n MyLib1
dotnet sln add MyLib1
dotnet new classlib -n MyLib2
dotnet sln add MyLib2
dotnet add MyLib1\MyLib1.csproj reference MyLib2\MyLib2.csproj
dotnet pack

These commands on a command line will create MyLib1.1.0.0.nupkg and MyLib2.1.0.0.nupkg, and then you can inspect these nupkgs any way you prefer (Visual Studio's Package Manager UI, NuGet Package Explorer, just open the nuspec file in a text editor) and see that MyLib1 has a dependency on MyLib2 version 1.0.0. At the time of pack, NuGet looks at the project reference, determines the package version of what MyLib2 would be if it was packed, and then uses that as the dependency version in MyLib1.

Basically in the simple cases where you have class libraries which is nothing more than one assembly (a bunch of .cs files that get compiled), you don't really need to think about NuGet, it just works the most naive way you'd expect it to.

Since the solution with the projects that are created as packed are all use ProjectReferences, it's not tedious to debug or develop, because NuGet doesn't even play a part until you're finished with debugging and development, and ready to publish.

There's a way to find out, publish the packages. But it's not exactly fully reversible. What goes to NuGet stays there forever.

Only nuget.org, but there's no reason why you have to use nuget.org for your packages. In fact, there's no way that companies creating propriatary software would publish their internal packages to nuget.org. But NuGet allows you to configure multiple sources, even remove nuget.org if you wish. There are commands like dotnet nuget add source... or dotnet nuget remove source... . You can also use dotnet new nugetconfig to bootstrap a new nuget.config file, and then use any text editor to edit the xml directly. The syntax is fairly simple, and it's all documented on docs.microsoft.com/nuget.

Anyway, taking my previous example, after creating MyLib1 and MyLib2 packages, copy them to some folder on your computer Get-ChildItem -recurse -filter *.nupkg | ForEach-Object { Copy-Item $_ c:\path\to\nupkgFolder } Get-ChildItem -recurse -filter *.nupkg | ForEach-Object { Copy-Item $_ c:\path\to\nupkgFolder } . Then create a new solution where you want to test the packages

dotnet new sln
dotnet new nugetconfig
dotnet nuget add source c:\path\to\nupkgFolder -n LocalNupkgs
dotnet new console -n MyApp
cd MyApp
dotnet add package MyLib1

Now, one problem is that NuGet assumes all package id-version are globally unique and immutable. This means if you try to test your package, find a bug, fix the bug, then try to test without changing the package version, NuGet will see the package in your global packages folder and use that old copy, so you won't see your fixes. This is why it's better not to test with PackageReference, just use ProjectReference. But anyway, if you get yourself into this situation, either delete the package from your global packages folder yourself, or you can use dotnet nuget locals global-packages --clear , which will clear ALL packages, not just the one you're testing. There hasn't been much demand for targeted deletion.

Another option is to set the globalPackagesFolder setting in your test solution's nuget.config. Unfortunately nuget.exe config hasn't been ported to the dotnet CLI yet, so either download nuget.exe from nuget.org/downloads, or just hand edit nuget.exe to set the folder to some other location, so it won't affect your normal development when you dotnet nuget locals global-packages --clear in your package testing solution.

This docs page also lists multiple options for hosting your own private feed, although a local folder is easiest for debugging. Many companies use a network file share instead of a server, but be aware that since nuget can't index package metadata on local folders or network shares, using Visual Studio's Package Manager UI will be slower than hosting an HTTP feed (that does have a search index), and I wouldn't be surprised if restore is also slower when the folder contains many nupkgs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM