I'm looking for a simple way to manage NuGet packages for the whole solution, to prevent conflicts between transitive NuGet packages when assembling all files into one installer.
When building a project all direct and indirect dependencies are analyzed and the NuGet resolution picks up the best matching version for each NuGet that is at least the same version as the lowest version and might also create binding redirects if necessary. (all good and fine)
The problem we have lately encountered was when we build the whole solution (200+ projects) at once, the resulting NuGet versions between all top level projects might not be identical. And due to the fact, that all resulting DLL and EXE files are installed into the same program files folder, the application can and will crash at runtime due to version mismatches when loading assemblies.
To better understand this issue I've created this sample repo.
The dependency graph looks like this:
Library1
Microsoft.IdentityModel.Tokens-5.2.1
Executable1
System.IdentityModel.Tokens.Jwt-5.3.0 (transitive reference: Microsoft.IdentityModel.Tokens-5.3.0)
Library1
results in: Microsoft.IdentityModel.Tokens-5.3.0
Executable2
Microsoft.IdentityModel.Tokens-5.2.1
results in: Microsoft.IdentityModel.Tokens-5.2.1
To demonstrate the problem, all projects compile to the same bin folder. When the whole solution is compiled and Executable2 is started, the application crashes, since the application expects Microsoft.IdentityModel.Tokens in version 5.2.1 but the actual version is 5.3.0.
For this constructed sample it is easy to find the problem and fix it with updating the Microsoft.IdentityModel.Tokens NuGet to the same version. (Manually, since Visual Studio Package Manager does not recognize this conflict in the consolidate tab).
But at a much greater scale it is far more complex to find those mismatches.
What we have found so far
Centrally managing NuGet package versions
Since it is not yet available, it cannot be used to solve the issue here.
Microsoft.Build.CentralPackageVersions
Unfortunately there is no IDE support for it, which makes managing NuGet packages very uncomfortable, which I would like to avoid if possible.
So my question is what is the best approach to avoid NuGet version conflicts between projects within the same solution?
We've experienced the same problem with some of our projects. We've been using Paket package manager since a couple of years and this has resolved that issue for us.
In short: you define on your solution level which packages you want to use in a file called 'paket.dependencies'. You can be very specific about versions, or let packet use the latest greatest. Then you can specify per project which NuGet package you want to use within that project in a 'paket.references' file. As the name implies, you reference to a package in the paket.dependencies file.
This will make sure, all references packages in your project will use the same package version. I hope this suits your needs as well.
Related
Some background:
At my company, I have been working the last few months with converting our C# libraries to function on .dll references instead of project to project references. To do this, we have created a local NuGet server which contains NuGet packages for all of our libraries projects. We have Jenkins jobs set up for every project which build new NuGet packages and add them to the server every time a change is made to one of them.
For working on a single project, this system works great. You only have to worry about updating your packages folder through Visual Studio's NuGet manager, and then the rest is just writing code and building.
The issue:
When you add a new reference, or update your packages through NuGet, NuGet automatically specifies that specific version of the project that you selected in NuGet. With the current system I have setup, rebuilding a project locally will then replace it's .dll in the packages folder so that all projects that reference it can see these new changes you're testing. However, the issue come in that locally built projects have a different version than our Jenkins built packages. Our local builds use a different versioning system from our Jenkins builds so that you can easily tell whether something was built using Jenkins, or if some of the .dlls came from a developer's build. Because of this different versioning scheme, the reference of projects to the project breaks, because the new .dll that was built locally has a different version than the .dll that was retrieved from the NuGet server.
Current Solution:
For the moment, I have resolved this through the addition of a pre-build step. Before every project builds, the project calls one of my PowerShell scripts, which goes through and adds <SpecificVersion>False</SpecificVersion> to every project reference in the project being built's .csproj file. This resolves the issue, but only in the sense of putting a bandaid on it. Instead of dealing with the consequences of the system, I wanted to prevent them ahead of time so that this isn't needed every time a project builds. I have tried researching a lot about NuGet packages specific versioning issues, but have not been able to find anything online even remotely close to what I am asking. This makes me think that I'm going about this wrong.
The question:
What can I do to solve this issue? Or am I doing something very wrong and dumb that could be easily avoided by using another system? Any suggestions or tips would be greatly appreciated
I am a dinosaur developer, so NuGet is relatively new to me, I am used to manage third parties open source libraries having a single project with the code or the binaries, that I will keep updated when necessary and this project publishes the dll(s) on a common folder from where I reference the libraries in all my projects. This makes easy to maintain the third party libraries and in my projects I just need to rebuild when I update the library and all goes OK. Now many open source projects publish their libraries on NuGet and it is easy to reference them in the projects, but I dread the fact that I have to download a copy of the library for each project in which I use it, this, in my opinion is something that can lead to chaos. Especially if I have 2 projects that build dlls that end up using 2 different versions of the same packages and are used both in an application with problems and conflicts. So my question to those who use NuGet from a longer time is:
Can I proceed with NuGet packages as with other libraries and create a project that references them, use it to publish the dlls in a single folder and then reference the dlls of the packages from my dlls and applications on the published folder.
I hope I've been clear. Thanks for any thoughts you can share on this topic
Sabrina
Having all your 3rd party libraries for all your projects in a single folder can lead to dll versions hell. If you update a single dll which contains breaking changes and which is referenced by other projects, then you will have fix/rebuild all projects that references it.
To resolve the issue with downloading the same packages for every project you can create a local repository and configure Visual Studio to use your local repository. So if your local repository contains a single version of log4net, you'll be able to use only that specific version. Even more you can configure repository to use a shared folder, in this case all developers and even your build server will be able to use that repository.
There are a lot advantages of using NuGet, such as saving a lot of space on your hard disks and others. For example I created NuGet packages for our internal framework, so all our projects just reference those packages, rather than each project has its own version in its bin folder.
We are developing a WPF application at work which has various "common" dependencies (Unity, Prism, etc.).
It's all fine when adding new projects and then setting up the NuGet package dependency per project but when it comes to upgrades, it's really painful as it means we have to go through each and every project, delete the old references and then refetch the latest packages from NuGet.
Today for instance, I was tasked with upgrading Prism from 5.0 to 6.0 (which has breaking changes anyway) and this meant, in addition to fixing all the namespace conflicts, etc. that I had to go through every project, delete the old references, add the new dependecies and rinse and repeat.
My question is, is there a smarter way to deal with this problem or is this the standard approach?
Many thanks in advance,
Update:
I am mostly concerned with "major" upgrades which don't show up on the package manager. Version 5.0 -> 6.0 upgrade would be treated as a major upgrade and hence, would not have an automatic update applied to it in the NuGet package manager.
I don't expect NuGet to be able to do this automatically for me since such upgrades may (and often do) include breaking changes but I would like to know if there's a way to do the major upgrades less painfully than deleting the references from the projects and the packages.config for every project and then re-adding them using NuGet. For a relatively large project, this is very time consuming and I was wondering if anyone had a better way of managing such dependencies.
If you use VS2013 like you say, you can manage ALL your NuGet packages by right-clicking on your Solution and selecting 'Manage NuGet Packages For Solution'. This brings up a dialog where you can view all packages installed for all projects in the solution and all packages that have updates available. When you do upgrade the packages, VS takes care of all the reference changes required. If the package has breaking changes, then you're still on the hook for fixing those.
Disclaimer: I've never worked on a WPF project/solution but for Web/Forms apps, NuGet packages are handled this way.
I can understand your pain because i had the similar problem like you, but there is no easy way. but certainly you need to break the process differently of your daily development and your dependency update roll-out.
for the project i worked on, I use the common repository path that shared among the solutions that you work on, and you need to delete all the solutions folder references in order to get a clean state.
For each solution you work on you need to modify the property group that point to the common target repository (i'm using relative path)
Once all the things setup, you can actually perform an update with a script(I'm using python run-time script)
you can actually look at setting up common nuget-packages-folder for reference updates for detail, but it seems like what you looking at for the automate process
I had a similar problem when trying to upgrade multiple packages with alpha channel issues in Xamarin Studio, which also does not have the niceties of VS 2015 NuGet manager. I ended up writing a very simple PowerShell script that I run multiple times a day.
#
# This script updates local ibGib NuGet packages for mobileGib Android app solution.
# For convenience in copy+paste in manager console:
# ../UpdateLocalNugetPackages.ps1
Update-Package commonGib
Update-Package ibGib
Update-Package languageGib.Biz
Etc.
I believe you could tailor your NuGet commands to fit your needs.
Also, just in case you aren't aware of it, you should definitely read the NuGet command line reference. I may be mistaken, but it sounds like your scenario is doable with the Update command.
I just switched from (an older) Microsoft.Bcl.Immutable NuGet package to System.Collections.Immutable and was surprised to find all these new package dependencies in my project:
System.Collections
System.Diagnostics.Debug
System.Globalization
System.Linq
System.Resources.ResourceManager
System.Runtime
System.Runtime.Extensions
System.Threading
They are listed as dependencies of the NuGet package, so they have a right to be there, yet they are obviously also already installed on my PC and my target environment (Azure btw) as they come with the framework.
I already have a large number of packages in my project and would like to avoid the additional overhead caused by these 8 packages, if possible (and without shooting myself in the foot).
Is it safe to remove these dependencies?
Do I now have to use these packages throughout my project because they might differ from their installed versions and some portion of my project might now use the wrong ones? (due to some DLL linking madness?)
Edit: Just for completeness, as there was a comment before: The dependencies are actual packages (not namespaces) and have to be downloaded, I'm targeting and compiling with .NET 4.6, working in VS2015. It's entirely possible though that something is outdated and the packages do not have to be loaded normally?
You are just seeing a side-effect of the Nuget package having to keep a lot of people happy. The package supports an enormous number of targets, it is proliferating rapidly as of late. I see support for Xamarin for OSX and iOS, Windows Phone 8.0 and 8.1, Windows Store, CoreCLR (the open source project), .NET 4.5, MonoTouch for iOS and Android and .NETCore (Silverlight).
These dependent packages just contain reference assemblies, the kind that are normally installed in your c:\program files x86\reference assemblies directory. The Nuget package doesn't take the chance that such a reference assembly might be missing and includes the whole kit and kaboodle.
After it is all downloaded, the package installer runs and adds the references you actually need in your project. Easy to see what happened, just open the References node of your project. If your targeted the desktop version of .NET 4.5 and up, the grand total of added references is one, just System.Collections.Immutable. Yes, you can remove them.
I'm having a particularly difficult refactoring session involving a C# solution with multiple projects in Visual Studio 2012. I needed to pull out a bunch of code into their own assemblies so that code could be shared across several projects, all in the same solution. However, no matter what I try, I get warnings for the projects that reference the new shared projects that "All projects referencing {shared project name} must install nuget package Microsoft.Bcl.Build".
I have been over the dependent projects and the shared projects with a fine-tooth comb, verifying in detail that they all use the same version and exact same DLL for the Microsoft.Bcl version 1.0.1.19 and Microsoft.Bcl.Async version 1.0.16 packages:
System.Runtime
System.Threading.Tasks
Microsoft.Threading.Task
Microsoft.Threading.Tasks.Extensions
Microsoft.Threading.Tasks.Extensions.Phone
The DLL paths are all resolved and identical. The XAP file does build but I still get that warning telling me that Microsoft.Bcl.Build is not referenced in the dependent projects, despite the fact that I can see that it is.
If I try instead to uninstall and then reinstall those two packages using NuGet for each project involved, I get references with empty paths and the warning icon for the 5 DLL references involved. For some reason NuGet adds the references but can't find the DLLs. Also, if I do this, I find myself with the problem frequently of having projects where I get the "Can't add reference" error when trying to add a reference. Then I have close and re-open the solution, and that leads to a "project failed to load" error. So I have to edit the project file manually, remove the faulty package import statements, and reload the project.
How can I fix this problem and what is the general technique for avoiding this headache in the future? Letting NuGet manage missing packages didn't help at al.
In case anyone else comes across this and #Swell's solution made you go "wtf":
I recently went through an older MVC project and updated it (updated razor, asp, http, etc. nuget packages). The project, independent of itself, built fine, but when i went to publish it failed with the OP's errors.
It turns out it's because I didn't update the *.Tests project associated with it (should have figured, though not sure why Tests is that closely tied to the project). So, to fix:
Right-click the Solution and manage nuget packages.
Go through all the packages that were updated in the web project and apply them to the other projects as well (each "Update" will display a tree with the applicable projects, I was fine just OKAY-clicking through).
Rebuild.
You should now be good and it shouldn't bark at you. Hope that helps others.
I just came throught the same issue and a bug is opened here: http://nuget.codeplex.com/workitem/3268
What I've done is the following, I added to the solution level the package Microsoft.Bcl.Build
In my dev env if you don't have the package loaded, just right click the solution and select manage nuget packages, you see a yellow bar with a restore button, just click it and you will be fine.
In my build script before compiling the project I run this command:
.\myproject\.nuget\NuGet.exe install .\myproject\.nuget\packages.config -OutputDirectory .\myproject\packages
This will restore solution level packages and you will be fine.
This should be fixed by the end of this summer in version 2.7 according to the issue report