简体   繁体   中英

How does visual studio/nuget decides what version(s) of the package to download/exact?

This is a C# project. I understand that nuget consults packages.config for the info to download/extract packages. However I noticed that it downloaded multiple versions for different .net platforms. For example, in the packages.config:

<package id="log4net" version="1.2.11" targetFramework="net461"/>

nuget downloads all the versions from net10 to net40. In addition, the location specified in the .csproj file is not consistent to that in the physical location.

In the above example, the location in the .csproj is something like:

src/packages/lognet.1.2.11/lib/log4net.dll

the physical location for the dll is, however:

src/packages/log4net1.2.11/lib/netXX-full/log4net.dll

XX can be from 10 to 40, as I said earlier, multiple versions of log4net were downloaded and extracted.

Due to the inconsistency, the project is doomed to fail, citing package not found error.

How should I do to fix this problem?

FYI: I asked a relevant but different question a few days ago.

C# project, compiler complaining missing reference to log4net

"direct and to the point" Answer : you shouldn't need to worry about it. When you install or upgrade a package in a project, NuGet tells the project system what to put in the csproj . Note that this is not the same thing as restoring packages. Installing packages in a packages.config project means Visual Studio will modify both the packages.config file and the csproj file. When you don't have the nuget package on your machine, when NuGet downloads and extracts it, it's called a restore, not an install. In the previous question you said that you cloned someone else's repo and you're trying to get it to build. You could ask them how/why the csproj doesn't match the log4net package on nuget.org. Or in Visual Studio, press ctrl-q to go to search, type "package manager console" and select it. Once it's initialised, select the project with the bad log4net reference in the "default project" dropdown, then type Update-Package -reinstall . This should fix it. Alternatively you can right click the project in Solution Explorer, select Manage NuGet Packages, uninstall log4net then install it again. You could also consider migrating from packages.config to PackageReference , which doesn't have this hint path problem that packages.config has.

long, detailed answer : when using NuGet, the word "version" usually refers to the package version, in this case 1.2.11. Looking at the package page on nuget.org , under version history we can see other versions like 1.2.10, 2.0.0, 2.0.1 right up to 2.0.8. Unless you have multiple projects that each reference a different version of the package, NuGet did not download multiple versions.

.NET has different versions of the runtime, some of which are not compatible with others, but these are called Target Framework Monikers (TFM), although people who don't work for Microsoft tend just to call them the target framework or something like that. It's similar to other managed runtimes or scripting languages like Java, Python, PHP, and so on, but possibly more complex because a huge number of TFMs were created in the past, mainly for different mobile devices that had different capabilities. Plus the Windows runtime is split into 3 "families" where TFMs are backwards compatible, but only within the same "family". The Nuget Client has a complex mapping of compatible TFMs that it uses to select the closest compatible TFM in the NuGet package for your project.

Another reason why a package might contain multiple dlls for different TFMs is because they want to use newer APIs in newer TFMs, while still allowing projects targeting an older TFM to use the package without the new APIs. For example, although net45, net46, net47 and soon net48 are all compatible with net40, net40 didn't have async-await. So, a package might have a net40 dll so projects targeting net40 can still use the package, but the package can also contain a net45 dll with extra async APIs. net1x, net 2x and net3x are so old, (as is net40 and net45) that packages rarely provide dlls for these old versions any more. However, log4net 1.2.11 was released in 2011, when these older TFMs were probably still common enough that it was worth providing compatibility for.

So, what you see in the lib folder of the log4net package isn't different versions of log4net, it's actually the same version of log4net but compiled for different TFMs. This increases the number of projects that can use the package.

There are several possibilities why the project you're using has a HintPath that doesn't exist. Given the information information you've provided so far, it sounds like either someone manually edited the csproj, or someone created their own log4net v1.2.11 nuget package which had the dll in a different location within the nupkg compared to the package on nuget.org. NuGet packages are designed to be immutable meaning downloading a nupkg with a specific package id (name) and package version should be identical to all other nupkgs with the same package id + version from any other NuGet feed. When it's not, you can get build errors when NuGet restores the package from a different source compared to the person who installed the package.

Finally, NuGet with packages.config is not designed to be edited manually. You should not edit and save the packages.config file or the References or HintPath in the csproj yourself. Use the NuGet Package Manager UI or Package Manager Console to install, uninstall and upgrade packages. There's a lot of logic in the NuGet client, not just asset selection, that you will get wrong if the package uses specific features.

In Visual Studio 2017, NuGet added a new way to reference packages, called PackageReference. You may need to go to Tools->Options, find NuGet Package Manager->General and either change the default package management format or enable "allow format selection on first package install". It should also be possible to right click many project types and have an option to migrate to PackageReference, but this hasn't been enabled for all project types (mainly ASP.NET). PackageReference does not support some features that packages.config supports, and some project types don't support PackageReference either. But in the most common cases it is supported, and if you can use it, it has several advantages, including no longer putting a hint path in your csproj and avoiding the specific problem you're currently having (on restore NuGet writes a file obj\\project.assets.json which contains the paths to the selected assets, which the compiler uses, meaning if you change your source code repository structure, simply doing a NuGet restore will fix it, whereas with packages.config you may need to reinstall every package in every project). Projects using the new SDK style that was introduced with .NET Core don't support packages.config at all, for whatever that's worth.

wow, I rambled for much longer than I expected I would. I hope it helped more than confused you.

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