Use solution relative packages folder with NuGet and project.json - version-control

I have a solution with a packages folder checked into source control. I changed some of the projects to use a project.json file rather than packages.config for defining dependencies. The projects are all normal .csproj projects, not DNX .xproj projects. Everything seemed to be working correctly however after updating a package I noticed that the new version wasn't added to the solution's packages folder. Instead it was added to NuGet's new shared packages folder in the user profile folder.
So the question is, how do I get NuGet to use the solution's packages folder rather than the shared folder?
Approaches I've tried so far without success:
Adding global.json file in the solution folder specifying "packages": "packages"
Setting <add key="disableSourceControlIntegration" value="false" /> in .nuget\nuget.config

NuGet 3.2 added support for specifying the shared global packages folder using an environment variable, NUGET_PACKAGES. You can set the full path to an alternative global packages folder, however I discovered that if you simply set the variable to "packages" then the NuGet tools in Visual Studio will treat it as a relative path under your solution folder. That allowed me to install and restore NuGet packages using the solution's packages folder.
Unfortunately building projects then gave me errors in Microsoft.NuGet.targets, unable to locate NuGet packages. The NugetPackagesDirectory property in msbuild doesn't seem to getting set. To work around this I added the following lines in to the C:\Program Files (x86)\MSBuild\Microsoft\NuGet\Microsoft.NuGet.props file:
<PropertyGroup Condition="'$(NugetPackagesDirectory)' == ''">
<NugetPackagesDirectory>$(SolutionDir)packages</NugetPackagesDirectory>
</PropertyGroup>
This will affect all solutions on the machine so an alternative would be to add those same lines in each project file or into a custom props file in the solution which you import into each project. This may also be needed for build servers too.
Although this works, the drawback is that the packages folder has a different structure, packages\<package_name>\<version>\ compared to packages\<package_name>.<version>\, and old or unused versions of packages aren't deleted after they're updated or uninstalled. Manually clearing the packages directory and then restoring required packages after any changes will achieve the same thing.
Personally this feels really hacky as it requires setting global settings for something which should be set on a per solution basis. NuGet is going to be updated at some point to support per solution package directories with project.json but in the meantime this you can use the above work around, or just stick with packages.config for the time being.

Related

How can a project get its own NuGet package instead of using the one the solution uses?

I have a C# project, TrendMasterCS2, built in VS 2019 that uses a DLL, TrendData, that relies on System.Data.SQLite.Core, which I get through the NuGet Package Manager. I opened the TrendMasterCS2 sollutio and uninstalled all NuGet packages from both the executable project and the DLL project. Then, I added the System.Data.SQLite.Core package to the TrendData project. I saved all files, and then opened the project file in Notepad. I saw this:
<Reference Include="System.Data.SQLite, Version=1.0.113.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
<HintPath>..\TrendMasterCS2\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.113.3\lib\net45\System.Data.SQLite.dll</HintPath>
</Reference>
This looks like a problem to me. If I ever want to use the TrendData DLL in some other solution, it's going to be carrying around this dependency on the TrendMaster2 folder. I think I can open TrendData by itself in VS2019 and add the NuGet package there, but is that what I have to do to ensure that TrendData is independent of TrendMasterCS2?
Consider to migrate from packages.config to PackageReference. (In Visual Studio, right click the packages.config and select Migrate packages.config to PackageReference...).
One benefit of PackageReference is that all packages will be restored to a global package cache directory and the tooling takes care of the actual reference path at compile time.
See https://learn.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference for details.
As an alternative you could create a nuget.config file and change the repositoryPath as described here: https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file#packagerestore-section
However I did not get managed to store packages in a project-local path using nuget.config.

Why does NuGet store packages in C:\Users\<UserName>\.nuget\packages?

I understand that it is now possible to configure a global package directory for all projects but I noticed that NuGet also puts files in my home directory. Is it possible to configure a single repo which will be used for all projects?
NuGet introduced a new way of package management in for project.json (now deprecated) and PackageReference-based projects (default .NET Core, .NET Standard).
Instead of creating a solution-local packages folder to which all packages are downloaded and extracted (alt: repositoryPath location in NuGet.Config override), all packages are downloaded to a global location (controlled by globalPackagesFolder in NuGet.Config) which is defaulted to %userprofile%\.nuget\packages (~/.nuget/packages on linux/Mac).
The idea is that you don't have to download packages multiple times and the csproj files no longer reference all individual files but just the package. .NET Core projects also do not need to copy the NuGet packages' assets because the generated .runtimeconfig.json file specifies the location of the global cache to look up the packages at runtime, so builds can be a little bit faster.
See this question, I believe everything will be clear after that
Setting up a common nuget packages folder for all solutions when some projects are included in multiple solutions

Automated injection of props/targets files not working for native C++ project

I am using automatic package restore in NuGet v2.8.50506.491 with Visual Studio 2013.
I have added a build folder to my package with a {package ID}.props file. However, the file is apparently not being injected into the vcxproj at restore time. The package and all its content are being restored correctly but none of the definitions are visible in vcxproj properties. This may be expected if property injection occurs in memory, but the build fails due to paths that are clearly defined in the props not having been inherited.
If I add an explicit reference to the props file in my local packages repository, the project builds successfully, therefore there is no issue with the paths in props file.
I have also tried adding the props within a "native" subfolder under build, also to no avail.
An extract from the nuspec:
<file src="build\MyPackage.targets" target="build\MyPackage.targets" />
I have also tried a targets file instead of/as well as a props file, but this does not work either.
I should add that I have defined Nuget.config in the sln folder, with an absolute path to my packages repository:
<config>
<add key="repositoryPath" value="C:\Packages" />
</config>
I was having this problem today, and eventually I realized that the names of my .nuspec and .targets files were different than the id of my package, which is apparently a problem. Renaming the .nuspec and .targets files to match the package id made NuGet start injecting into the vcxproj correctly. I'm not sure which of the two files was the problem, or if it was both, but it's working correctly now that all three names match.
Injection of .targets and .props file references happens only at the time when you install the NuGet package. This is the same as with .NET projects where assembly references are created only at package install time.
Later when you build the project the package restore mechanism merely downloads and extracts the NuGet package so that the previously "dangling" .target / .props / assembly references become valid references.

NuGet package files not being copied to project content during build

I am building an MVC4 web application with VS2012 professional with NuGet Package Manager version 2.2.31210. I have multiple projects in my solution, all sharing various packages I installed using NuGet. One of my projects is an MVC4 web application where I am using packages such as bootstrap, jquery UI, etc, all installed using NuGet.
When I clone a fresh copy of my entire solution from my repository and build my MVC4 project, the package restore feature seems to be working: it creates the packages directory under the solution direcotry and populates it will all the versions of the packages I expect to see. However, the content files do not get copied to the appropriate places in the MVC app directory. The weird thing is that it does create directories for the content, but does not copy the content files themselves.
For example, I am using the Twitter Bootstrap package which appears in the packages/Twitter.Bootstrap.2.2.2. In the MVC project a directory called bootstrap (containing css, img, and js directories) gets created in the Content directory. But, no css or js files are copied into those directories!
Does anyone have a clue what magic incantation I must utter to get the build to copy these content files from the NuGet packages directory?
This is a very common issue we are all having. I've created an MSBuild Task NugetContentRestoreTask that will do this trick for you. Run the following command in the Package Manager Console:
Install Nuget Content Restore MSBuild Targets
PM> Install-Package MSBuild.NugetContentRestore
The only thing left is to call it from your BeforeBuild Target with something like this:
Project File Targets
<Target Name="BeforeBuild">
<NugetContentRestoreTask SolutionDir="$(SolutionDir)" ProjectDir="$(ProjectDir)" />
</Target>
You can take a look at the source repo and find it on nuget.org
Additional Content Folders
This nuget only includes the default folders scripts, images, fonts, and content, it is not a recursive directory includes. For additional content subfolders - you must assign the property AdditionalFolders.
<Target Name="BeforeBuild">
<NugetContentRestoreTask SolutionDir="$(SolutionDir)" ProjectDir="$(ProjectDir)"
AdditionalFolders="less;sass;common" />
</Target>
I have found a workaround, but it is ugly. By executing the following command in the NuGet Package Manager Console: Update-Package -Reinstall all the files are indeed copied to their proper places within the Mvc project Content and Scripts directories.
Unfortunately, this is risky because you are likely to end up with the wrong versions of certain packages. For example, in my case after the command finishes executing (which takes quite a while by the way), I end up with jQuery version 1.4.4. This is way old, and I assume it must be an explicit dependency of some other package that is being updated. So it appears that the order in which the packages actually get updated by NuGet is significant (it does not appear to parse the entire dependency tree for all packages and pick only the latest versions from the union of all dependencies, which seems like it would be the preferred behavior). Rather, as the command executes I see it replacing the jQuery package several times with different versions as it works its way through all the packages and their dependencies, only to end up with a very old version.
A similar approach is the execute the Update-Package -Reinstall command explicitly for each package that is causing my problem, but this is incredibly tedious and error prone.
The NuGet Package Restore feature should yield the same result as manually executing the Install-Package or Update-Package -Reinstall command for a package, but it does not.
I don't like to have the thirdparty JavaScript files under source control either. Thats why I've followed Jeff Handley advice in http://nuget.codeplex.com/workitem/2094 to create a solution my self. I didn't go the executable way, but created a nuget solution level package which does the trick.
http://www.nuget.org/packages/Baseclass.Contrib.Nuget.GitIgnoreContent/
It's tied to git, as it automatically updates the .gitignore file.
Short description:
Ignore nuget content files in git:
Generate entries in the .gitignore file to exclude nuget content files from the source repository
Restore nuget content files before building (Automatically in VS and manually with a powershell script
I've written a blog post describing how to use it.
http://www.baseclass.ch/blog/Lists/Beitraege/Post.aspx?ID=9&mobile=0
In Visual Studio 2015 Update 1, they now support contentFiles. The caveat with this is that it only works in projects that use project.json.
In reference to the problem that you are having, there is a good blog post that explains why you see this behaviour: NuGet Package Restore Common Misconceptions.
For my projects it turned out that content files work with PackageReferences only:
Existing project with nuget references via packages.config
Installed NuGet package with content files
Build project
No content files in output directory
Conversion of packages.config to PackageReferences
Build project
Content files have been copied to output directory
IDE is Visual Studio 2017. The project is an application project which means it is in the old csproj format.

Create nuget package with multiple DLLs

Let's say I have a project with this structure:
MyLibrary\
MyLibrary.sln
MyLibrary.Core\
MyLibrary.Core.csproj
MyLibrary.Extensions\
MyLibrary.Extensions.csproj
MyLibrary.Tests\
MyLibrary.Tests.csproj
I want to create a single NuGet package which packages MyLibrary.Core.dll and MyLibrary.Extensions.dll. I can't seem to figure out how to get NuGet to do this. I've tried building a spec file manually and I've tried building one using "nuget spec MyLibrary.Core.csproj". I've tried adding all of the DLLs to a lib/ folder which I understand to be the convention-based mechanism for adding DLLs to the package. In every case I can get the MyLibary.Core.dll to get into the package but the MyLibrary.Extensions.dll does not end up packaged along with it.
TLDR: What is the best practice for creating a NuGet package with multiple projects / assemblies? Is there a tutorial out there that focuses on this? The tutorials I've found all focus on simple single-project demos.
You'll run NuGet on a single project (or nuspec file), but it supports pointers to other projects via the file element. This element uses the names of your project's References, so you avoid having to a) find the location of other project files, and b) copy files to a particular place as a post-build step.
Supposing you have a nuspec file for MyLibrary.Core.csproj, and it references MyLibrary.Extensions and MyLibrary.Tests such that they end up in the bin directory after a build:
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
...
</metadata>
<files>
<file src="bin\Release\MyLibrary.Extensions.dll" target="lib\net40" />
<file src="bin\Release\MyLibrary.Tests.dll" target="lib\net40" />
</files>
</package>
With this setup, all of your references should end up in the appropriate place in the NuGet package. You still have the hard-coded 'Release' in there, but I'd wager most probably don't distribute NuGet packages of their debug builds anyway.
Did you generate a blank nuspec file with:
nuget spec
If you use that file and then put your dlls in a folder under it named lib, it will package them up.
I had a little trouble with trying to generate a nuspec file from a project or dll. Also, if you manually reference any files in the nuspec file, the conventions are not used. This is probably the problem with nuspecs generated from dlls or projects.
Also, if you are trying to run this from a build script that executes in a different folder, you can tell nuget the location of your .\lib folder via the -BasePath command line:
build\nuget.exe pack nuget\Company.Project.nuspec -BasePath nuget\
Have you tried NuGet Package Explorer? Might be the easiest way:
http://nuget.codeplex.com/releases/view/59864
It seems your problem is the same as this question: Why doesn't nuget include the referenced project when packing?. If so, you can use the -includereferencedprojects option (See http://docs.nuget.org/docs/reference/command-line-reference#Pack_Command).
I recently published a solution for this...
My solution enables automatic creation of NuGet packages when you build the solution where each package can contain multiple assemblies, references to both external NuGets and NuGets created during the same build and even include the source code for debugging.
In your case, all you will need to do is add a new class library project to your solution, reference the projects you want to package, then add a post build event.
You can find an article with a walk-through guide here
and the source code here.
i have some tutorial how i did it with windows and visual studio:
create local folder and call it packages like: c:/packages//lib - important to create another folder in folder call it lib and past there dll.
open nuget package explorer - https://npe.codeplex.com/downloads/get/clickOnce/NuGetPackageExplorer.application
the ui very intuitive just add dll and export it to /lib (for tutorial https://blog.zwezdin.com/2014/building-nuget-packages-with-gui-tool/ it in russian but see on pictures the flow it's about 3 clicks)
it will create nuspec file
open GIT BASH - https://git-for-windows.github.io/ and navigate to: cd c: => cd packages (the path of )
*maybe on windows you will need provide developer options for windows's linux stuff (https://www.howtogeek.com/249966/how-to-install-and-use-the-linux-bash-shell-on-windows-10/)
in GIT BASH enter command: nuget add -source [options]
where: : the full name of nuspec (include .nuspec)
and: the path of folder lib in folder (c:/packages//lib)
after the action ended successfully
in GIT BASH enter another command:
nuget pack .nuspec
not in this folder you have .nupkg file.
How to install a Nuget Package .nupkg file locally? - tutorial how to add it to visual studio.
I had the same problem and I decided to create Nuget which will allow to create other nugets from chosen project.
Package is deployed on the Nuget.org site. After referencing it in the project You need to add nuspeck file to the projects which should generate the projects.
Project with the required nuspeck file
Last thing which should be done by you is invoke command Create-Nuspec in Package Manager. Than the powershell module will take all libraries which are result of the build it will add also the required dependencies and create the nuget in the output directory.
Description about this package is placed here.
I had an issue when adding extra dlls references to a Nuget packages, and testing the package on a sample project, the extra dlls was not being added apparently, no matter the way that I create the Nuget Package.
Then I released that when you uninstall and install again a local Nuget Package with the same version number the changes no take effect, the extra dlls are not added.
So each time you uninstall the package, close visual studio and clear the Nuget Cache,
How to clear NuGet package cache using command line?
Then open again Visual Studio and reinstall the local package to make the change takes effect.
Or make the package version to increase each time to be for Visual Studio to recognize your changes.
For example:
Package-1.0.0
Package-1.0.1
Package-1.0.2
.....
To create a Nuget package from a sample project there are some ways, for example:
Right click to your Visual Studio project and choose the "Pack" option
Then install the nuget package explorer:
https://www.microsoft.com/es-ec/p/nuget-package-explorer/9wzdncrdmdm3?activetab=pivot:overviewtab
And add manually your extra references (dlls files) to your specific targets.
Create a nuget package using a .nuspec file how specified in the documentation:
https://learn.microsoft.com/en-us/nuget/guides/create-packages-for-xamarin
<files>
<file src="Plugin.LoggingLibrary\bin\Release\Plugin.LoggingLibrary.dll" target="lib\netstandard1.4\Plugin.LoggingLibrary.dll" />
<file src="Plugin.LoggingLibrary\bin\Release\Plugin.LoggingLibrary.xml" target="lib\netstandard1.4\Plugin.LoggingLibrary.xml" />
<file src="Plugin.LoggingLibrary.iOS\bin\Release\iOsDependence.dll" target="lib\Xamarin.iOS10\iOsDependence.dll" />
<file src="Plugin.LoggingLibrary.Android\bin\Release\AndroidDependence.dll" target="lib\MonoAndroid10\AndroidDependence.dll" />
</files>
In your files part add your .dll files.
And dont forget, each time you uninstall and install again the nuget package from your local source.
Or you increase the version of the package each time:
Or close Visual Studio, clean the nuget cache and Rebuild your project.
In order to take effect the changes.