project.json specify exact version of NuGet dependency - nuget

When using a packages.configfile to specify NuGet dependencies I'm able to provide the allowedVersions attribute to specify a SemVer string defining the range of versions I want to be able to update to. By using [] I'm currently able to effectively pin my package to a single version. Eg:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Common.Logging" version="3.3.0" allowedVersions="[3.3.0, 3.3.0]" />
</packages>
Now that in .net core projects we have project.json to specify NuGet dependencies (however short lived it may be), how can I pin a NuGet dependency to a version such that dotnet restore doesn't update my application to a new version of one is available from my package source?
{
"version": "1.0.0-*",
"dependencies": {
"NETStandard.Library": "1.6.0",
"Newtonsoft.Json": "9.0.1" //how can i pin to 9.0.1 ??
},
}
Figure #2 in this nuget documentation stronly implies this is possible, but doesn't provide the syntax to do it.
-- UPDATE --
I tested this with two .net core class libraries and my local file system as a package repository. I created a class library called UpdateMeDependencyLib and packaged it as v1.0.0, and I consumed it from a second project via nuget. Below is the project.json from the 2nd class library consuming UpdateMeDependencyLib
{
"version": "1.0.0-*",
"dependencies": {
"NETStandard.Library": "1.6.0",
"UpdateMeDependencyLib": "1.0.0"
},
"frameworks": {
"netstandard1.6": {
"imports": "dnxcore50"
}
}
}
I then updated UpdateMeDependencyLib to version 1.1.0 and repackaged, so there is now a v1.0.0 and a v1.1.0 nuget package on my local system. After creating v1.1.0 of UpdateMeDependencyLib I now get the following experience
Compiling the project in Visual Studio (with no changes to consumer project.json) that consumes UpdateMeDependencyLib outputs v1.1.0 to its bin directory
If I force a package restore on the consumer library I now get a Nuget warning "NU1007 Dependency specified was UpdateMeDependencyLib >= 1.0.0 but ended up with UpdateMeDependencyLib 1.1.0"
So it would appear simply using "1.0.0" in my consuming library doesn't pin it and it will automatically get updated when a new version appears in my NuGet source.

You need to use the following notation for your ref
"UpdateMeDependencyLib": {
"version": "1.0.0",
"target": "package"
}
As the two projects are in the same solution, the system doesn't use your local package repo to resolve the dependency. It directly uses the project as reference. Because the reference 1.0.0 no longer exists in the solution, (and because "UpdateMeDeepencyLib": "1.0.0" means >= 1.0.0), it use the Nuget rule "Lowest applicable version" and resolve the dependency by referencing the 1.1.0 project. Note the icon of the UpdateMeDependencyLib in the dependency tree is not the nuget one.
What I can't figure out is, how we can stricly set the dependency to 1.0.0 and, in this case, break the build.

To lock in a specific version, place the version number inside square brackets.
"UpdateMeDependencyLib": {
"version": "[1.0.0]",
"target": "package"
}
You will need to do a restore packages after updating.

Related

Mirroring pub.dev packages to a custom package repository

As of Dart 2.15, you can create your own package repository.
https://dart.dev/tools/pub/custom-package-repositories#publishing-to-a-custom-package-repository
We need to mirror the subset of pub.dev packages (for corporative security reasons).
But there's no information, how to do a package mirroring.
Should I fork a GitHub source and publish every allowed package versions manually? It looks exremely annoying and time-consuming. And what about transitive dependencies? Should I upload all of them too?
I also found this article: https://medium.com/dartlang/hosting-a-private-dart-package-repository-774c3c51dff9 , it describes the pub.dev mirroring scenario too, but doesn't explains how to do it.
I don't know if this is the answer you are looking for, but I believe that with some experimentation this could be scripted using the APIs described in the dart package repository specification:
https://github.com/dart-lang/pub/blob/master/doc/repository-spec-v2.md
For example, you can query all versions of a package like so:
curl https://pub.dev/api/packages/test
{
"version": "1.23.1",
"pubspec": {
"name": "test",
"version": "1.23.1",
...
"dependencies": {
"analyzer": ">=2.0.0 <6.0.0",
...
"test_core": "0.4.24"
},
"dev_dependencies": {
...
}
},
"archive_url": "https://pub.dartlang.org/packages/test/versions/1.23.1.tar.gz",
...
}
....
}
You can then use the archive_url for the version(s) you want to download the package, potentially iterating over the dependencies and downloading them as well.
You would then need to upload each package version you downloaded to your private repo. This can be done by first doing a GET on the new package submission URL:
curl https://my-private-repo.tld/api/packages/versions/new
{
"url": "https://my-private-repo.tld/api/packages/versions/newUpload",
"fields": {}
}
And then POST the form described by fields plus the archive you previously downloaded to the url provided in the response. Note that when I test this against unpub, the fields map is empty, but depending on your private repo implementation that may be different.
One could imagine a script that starts with a list of packages to mirror, downloads them, potentially also downloads their dependencies, and then uploads them all to the private server.
For transitive dependencies it probably depends on your security requirements. If you use PUB_HOSTED_URL=https://my-private-repo.tld then running flutter pub get will download any dependencies it can find from your private repo, and any other dependencies from pub.dev. If that is not acceptable, then you'll probably need to upload them all.

Using NuGet restore with lock files gives "NU1004: The packages lock file is inconsistent with the project dependencies" error

I am getting this error when I use the -LockMode switch with the nuget restore command.
NU1004: The packages lock file is inconsistent with the project
dependencies so restore can't be run in locked mode. Disable the
RestoreLockedMode MSBuild property or pass an explicit
--force-evaluate option to run restore to update the lock file.
What I am trying to achieve is to automatically upgrade my nuget references by using wildcards but use specific versions when I want to re-build my project from known sources. this blog posts describes how this can be achieved Enable repeatable package restores using a lock file.
When I use -UseLockFile & -LockMode on a simple solution with just one project it works as expected, the issue arises when I start adding another project to the solution.
Here're the steps:
I have published my package to an Azure DevOps feed and I have the following versions listed:
1.0.1-ci.1
1.0.1-ci.2
I have created a .Net 3.1 console app that references my package using wild cards, i.e. <PackageReference Include="My.Package" Version="1.0.*-ci.*" />
Running the command nuget restore -UseLockFile -ForceEvaluate creates the packages.lock.json with the right reference (I am using -ForceEvaluate in order to ensure it always resolves to the latest version available on the feed), the contents of the lock file of my console project are:
{
"version": 1,
"dependencies": {
".NETCoreApp,Version=v3.1": {
"My.Package": {
"type": "Direct",
"requested": "[1.0.*-ci.*, )",
"resolved": "1.0.0-ci.2",
"contentHash": "4HQuN7LNoZT9Z+MOL/Yig79FehhXBZmi26j3VtWR9Cgz8k5irWspSQ8aasVbNkYp7AgA2XaDQdr/cnwJnPilpQ=="
}
}
}
}
I then publish a new version of My.Package (1.0.1-ci.3) and run the command nuget restore -LockedMode, and the version resolved is still 1.0.1-ci.2, and if I then run nuget restore -ForceEvaluate it will resolve as expected to 1.0.1-ci.3, so far so good!
The issue arises when I add a class library to my solution which uses the same package reference, i.e. <PackageReference Include="My.Package" Version="1.0.*-ci.*" />, when I run restore -UseLockFile -ForceEvaluate my packages.lock.json file is updated to include the project dependency:
{
"version": 1,
"dependencies": {
".NETCoreApp,Version=v3.1": {
"My.Package": {
"type": "Direct",
"requested": "[1.0.*-ci.*, )",
"resolved": "1.0.0-ci.3",
"contentHash": "4HQuN7LNoZT9Z+MOL/Yig79FehhXBZmi26j3VtWR9Cgz8k5irWspSQ8aasVbNkYp7AgA2XaDQdr/cnwJnPilpQ=="
},
"classlibrary1": {
"type": "Project",
"dependencies": {
"My.Package": "1.0.0-ci.0"
}
}
}
}
}
While the contents of the lock file of the Class Library project are:
{
"version": 1,
"dependencies": {
".NETCoreApp,Version=v3.1": {
"My.Package": {
"type": "Direct",
"requested": "[1.0.*-ci.*, )",
"resolved": "1.0.0-ci.3",
"contentHash": "4HQuN7LNoZT9Z+MOL/Yig79FehhXBZmi26j3VtWR9Cgz8k5irWspSQ8aasVbNkYp7AgA2XaDQdr/cnwJnPilpQ=="
}
}
}
}
After this when I try running restore -LockMode I get the NU1004 error mentioned earlier.
Doing what the error message suggests and use -ForceEvaluate would clearly break what I wanted to achieve, yet I can't imagine that this relatively simple scenario is not covered by NuGet, so I would guess I am doing something wrong, does anyone have any ideas of what I could try to make this work?
It sounds like you're adding a new dependency then running nuget restore -LockedMode without first running nuget restore -ForceEvaluate.
It's not obvious what NuGet should do in that case - you're telling it you only want to use the dependencies in your lock file but you've also added new dependencies too.
It sounds like this would typically fail the restore:
If locked mode is set, restore will either get the exact packages as listed in the lock file or fail if it cannot. For example, if you updated the defined package dependencies for the project after lock file was created
https://devblogs.microsoft.com/nuget/enable-repeatable-package-restores-using-a-lock-file/#why-use-a-lock-file
You might have hit a corner case if the only transitive dependency of your new dependency is one that's already in the lock file but at a different version.
In general though, whenever you add new dependencies you're going to need to update your lock file, then after that you should be set to carry on running nuget restore -LockedMode.

Unable to find nuget folder

I'm unable to find some nuget packages (VS 2019, asp.net core 2.2). I found that System.ComponentModels.Annotations can't be found in my .nuget folder and in VS, there is no "expand" arrow next to it like all the other packages:
In my .nuget folder:
I've tried clearing out my packages folder and re-building to get all the packages. I've tried update-package -reinstall. I've tried Installing system.componentmodel.annotations directly (rather than having it install as a dependency). My solution builds fine, but I can't find this package anywhere on my harddrive. I've also noticed that Microsoft.AspNetCore.Razor.Design is exhibiting the exact same behavior.
When NuGet restores a project that uses PackageReference for packages (all SDK-style projects, and opt-in for traditional projects), it writes the obj\project.assets.json file, which is what MSBuild uses to complete the rest of the build.
Looking at the packageFolders section of my test project, I see this:
"packageFolders": {
"c:\\git\\test\\globalPackages\\": {},
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder": {}
},
note that I have a nuget.config that redirects my global packages folder away from my user profile global packages folder, so temporary/fake packages I create don't pollute my real dev environment. FYI in case you're wondering why you don't see c:\users\zivkan\.nuget\packages.
But notice that there are two package folders.
Looking for System.ComonentModel.Annotations in the libraries section of project.assets.json, I see:
"System.ComponentModel.Annotations/4.5.0": {
"sha512": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==",
"type": "package",
"path": "system.componentmodel.annotations/4.5.0",
"files": [
// list of every file in package
]
},
see the path says system.componentmodel.annotations/4.5.0, which means it could be in either or both of c:\git\test\globalPackages\system.componentmodel.annotations\4.5.0 and/or C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.componentmodel.annotations\4.5.0.
For your use-case of trying to load it in Powershell, you can try to load one of the assemblies in the lib\* directory. Pick a TFM you think is compatible with your version of Powershell.
As for the reason that Solution Explorer doesn't have a twisty to expand the package, go find the package in the targets section of the project.assets.json and you'll see this:
"System.ComponentModel.Annotations/4.5.0": {
"type": "package",
"compile": {
"ref/netcoreapp2.0/_._": {}
},
"runtime": {
"lib/netcoreapp2.0/_._": {}
}
},
In other words, the package is not bringing in any assets or additional NuGet dependencies. Therefore nothing to expand in Solution Explorer.
In this specific case it's because netcoreapp2.0 has the assembly built-in to the runtime, and the Microsoft.NETCore.App package has the compile-time metadata for it. This is why I asked why you are looking for the package. If you use project.assets.json to find the exact System.ComponentModel.Annotations.dll that the build uses during compile, you'll find a metadata-only reference assembly that can't be loaded. But I gave insturations above on how to find the package directory and you can look for a loadable dll in one of the lib\* directories to try to load in Powershell.

Can't install created nuget package- The dependency XY 1.0.0 does not support framework .NETCoreApp,Version=v1.0

My Project XY is targeting .NET Standard 1.3 and contains the following dependencies:
{
"supports": {},
"dependencies": {
"Microsoft.NETCore.Portable.Compatibility": "1.0.1",
"NETStandard.Library": "1.6.1",
"System.Data.Common": "4.3.0",
"System.Data.SqlClient": "4.3.0",
"System.Reflection.TypeExtensions": "4.3.0",
"System.Runtime.Serialization.Xml": "4.3.0"
},
"frameworks": {
"netstandard1.3": {
}
}
}
I'm using NuGet Version: 3.5.0.1938 with the following command: nuget pack XY.csproj -IncludeReferencedProjects which works fine.
When installing the created nuget package to a .NET Core Console Application (or UWP) Project, it will fail with the error message:
package XY 1.0.0 is not compatible with netcoreapp1.0
(.NETCoreApp,Version=v1.0). Package XY 1.0.0 supports: portable50
(portable50,Version=v0.0) error: One or more packages are incompatible
with .NETCoreApp,Version=v1.0.
I don't know from where "portable50" is coming. Also I can't find with Nuget Package Explorer something with "portable50".
Please note, I can add the XY .netstandard project as reference to the NETCoreApp solution and use it. It seems that the nuget package manager does something wrong?

Building Google Analytics package in ASP.NET Core 5.0

I am trying to include Google Analytics API package in my MVC 6 application. I've tried to include all the dependencies or to let it install trough NuGet Package Manager. In either case, when i build the solution, I get an error: Error CS0246 The type or namespace name 'Google' could not be found (are you missing a using directive or an assembly reference?) ProjectName.ASP.NET Core 5.0
Any idea what dependencies I need to include for it to build in ASP.Net Core 5.0?
Here is what i have in my project.json file:
"dependencies": {
...
"Microsoft.Net.Http": "2.2.28.0",
"Microsoft.Bcl": "1.1.9.0",
"Microsoft.Bcl.Build": "1.0.21.0",
"Microsoft.Bcl.Async": "1.0.168.0",
"Google.Apis.Analytics.v3": "1.9.0.1100"
},
...
"frameworks": {
"aspnet50": {
"dependencies": {
}
},
"aspnetcore50": {
"dependencies": {
"Newtonsoft.Json": "6.0.8.0"
}
}
},
Similar issue to the one described here: Problems with RavenDB.Client reference in asp.net 5.0 project.json
Adapting my answer from there:
The problem is that you referencing Google.Apis.Analytics.v3 in the top level dependencies node in project.json. That means that those dependencies are applicable to both Desktop CLR (aspnet50) and CoreCLR (aspnetcore50).
When you build an ASPNET 5 project, all configurations are built, not just the "active" one. Mostly sure Google.Apis.Analytics.v3 works only with the Desktop CLR so move it under a dependencies node under that configuration.
"dependencies": {
....
},
"frameworks": {
"aspnet50": {
"dependencies" : {
"Google.Apis.Analytics.v3": "1.9.0.1100"
}
},
"aspnetcore50": {}
}
Then you might have to either use some conditional blocks in your code (#if ASPNET50) or remove CoreCLR all together.
Then you might have to either use some conditional blocks in your code (#if ASPNET50) or remove CoreCLR all together.