How can I configure a single packageRepository directory for multiple solutions? - visual-studio-2013

Given a working copy that contains multiple Visual Studio solutions in different directories, how can I configure the working copy so that restoring packages in any solution will result in the packages being downloaded to one and the same directory?
The setting in NuGet.config that controls where packages are downloaded and expanded, is called packageRepository (reference).
Here's the places where I added a NuGet.config file (or added the setting to an existing file) and it did not have any effect:
the same directory as the solution file
a parent or ancestor directory of the solution file
the .nuget directory that is in the same directory as the solution file
I am looking at two ways of restoring packages:
Using Visual Studio (the magic 'restore' button in the Package Manager COnsole)
Using MSBuild (where .csproj files are altered to include the $(SolutionDir).nuget\nuget.targets file)
Is it possible to configure NuGet package restore (either or both methods) to download and expand packages to the same location?

Related

Azure pipeline: msbuild does not copy one DLL in _PublishedWebsites

I have a strange behavior with msbuild on my Azure Pipeline.
I'm using Azure Pipeline with Self-hosted Windows agents.
Configuration:
My Visual Studio .sln contains two C# projects:
WebService (Rest API)
Business layer
In addition, the Business layer has dependencies on 2 others projects.
Kernel.DataModel
Kernel.DataAccess
The Kernel.DataAcess layer is using the NuGet package "Microsoft.SqlServer.Types" (14.0.314.76)
The Reference "Microsoft.SqlServer.Types" in the project Kernel.DataAccess has "Copy Local = True". Therefore the DLL file should be copied in the output (release) directory.
The problem:
When I run the Azure Build pipeline, the file "Microsoft.SqlServer.Types.dll" is not copied in the "_PublishedWebsites" directory.
To convince myself, I decided to run the same Pipeline on another build machine by changing the Agent Pool. At my surprise the DLL was present in the "_PublishedWebsites" on the second build machine.
Furthermore, I decided to manually run the msbuild command on my local computer and the the DLL was also present in the "_PublishedWebsites...\bin" on my local machine.
Log files:
I also looked at log files on the Build machines and on my local computer.
First build machine -> The DLL file is simply not copied !
Second build machine -> The DLL file is copied from this location.
Copying file from "C:\Program Files (x86)\Microsoft SQL Server\140\SDK\Assemblies\Microsoft.SqlServer.Types.dll" to "F:\AgentLatestBuild\A1\_work\28\b\_PublishedWebsites\ApiProject\bin\Microsoft.SqlServer.Types.dll".
Local machine ->
_CopyFilesMarkedCopyLocal:
Copying file from "C:\TFS\Repos\Src\Project\**packages**\Microsoft.SqlServer.Types.14.0.314.76\lib\net40\Microsoft.SqlServer.Types.dll" to "E:\tfs\build\Microsoft.SqlServer.Types.dll".
Copying file from "E:\tfs\build\Microsoft.SqlServer.Types.dll" to "E:\tfs\build\_PublishedWebsites\ApiProject\bin\Microsoft.SqlServer.Types.dll".
As you can see:
On the second build machine, msbuild is not using the NuGet packages folder but it's using "C:\Program Files (x86)\Microsoft SQL Server\140\SDK\Assemblies\Microsoft.SqlServer.Types.dll"
On my local machine, the DLL is copied from the NuGet packages folder.
Here are my questions:
How msbuild.exe is selecting the source/location of the DLL ?
Is there a way to force msbuild to first use the NuGet packages instead of any others folders ?
I think msbuild should first look in the NuGet packages folder and if the DLL is not found, then it should try to find it from somewhere else. (C:\Program Files (x86), GAC, etc..)
Finally, do you have any idea why the "Microsoft.SqlServer.Types.dll" is not copied at all on the first build machine. The DLL is present in at least three locations. (ie: NuGet packages folder, C:\Program files\ and it is also in the GAC).
It looks like msbuild is lost in the dependency tracking and can't find the file or it won't copy it for some other reasons.
Thanks for your help.
Is it possible that your *.csproj is targetting the wrong HintPath?
Could you check if you have something like this:
<Reference Include="Microsoft.SqlServer.Types">
<HintPath>..\packages\Microsoft.SqlServer.Types.YOURVERSION\lib\net40\Microsoft.SqlServer.Types.dll</HintPath>
</Reference>
thanks

Move packages folder inside the solution folder

Visual Studio 2017 / ASP.NET Web Application solution.
The default folder structure is as follow:
What I want to achieve is keeping everything (including packages) inside the WebApplication1 folder (except WebApplication1.sln file).
I know about NuGet.Config but unfortunately it seems mandatory to place this file next to the .sln file. I would have preferred to place this file inside of WebApplication1 folder. I would like to have ONLY ONE file outside of the solution folder: the WebApplication1.sln file.
I know about NuGet.Config but unfortunately it seems mandatory to place this file next to the .sln file. I would have preferred to place this file inside of WebApplication1 folder. I would like to have ONLY ONE file outside of the solution folder: the WebApplication1.sln file.
I understand your requirement, you want to have only WebApplication1.sln file outside of the solution folder. But if you are using nuget.config to change the location of packages, this nuget.config file will be placed in a folder outside the solution folder, which is not what you want.
To resolve this issue, you can put this nuget.config file outside the solution folder, which is not necessary to put this file next to the .sln file, for example, you can put this file in the root directory of the C drive with following content:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositoryPath" value="C:\Users\<UserName>\source\repos\WebApplication1\WebApplication1\packages" />
</config>
</configuration>
Then close your Visual Studio and delete the packages folder in the solution folder, re-open the Visual Studio and open the your solution, right click on the your solution, select restore the nuget packages, all the nuget packages will be place inside the solution folder and the only file outside of the solution folder is the WebApplication1.sln file:
Note: This method has its own limitations, we have to use absolute path in the nuget.config file and this setting will still be work for other solutions.
Besides, you can try to use PackageReference instead of packages.config in project files. With PackageReference, your packages are point to the global package folder C:\Users\<UserName>\.nuget\packages, so that we do not need add a nuget.config file to change the package folder.
To use the PackageReference, go to the Tools->NuGet PackageManager->Package Manage Settings:
Hope this helps.
My understanding of why the visual studio put the package folder next to .sln but outside WebApplication1 folder is, WebApplication1 is a project in the WebApplication1 solution. But one solution can contains multiple projects. In your case the project name happens to be same as the solution name(due to when you create this project and solution in vs). So if you have multiple projects in this solution but want to share some nuget packages, then it make sense for the package folder to be outside the project folder.
Thant's my understanding for why vs has this default setting. Hope that helps.

How do I set Visual Studio to build a NuGet package?

How can I get Visual Studio to build a NuGet package for my library component on build?
I’m using a Portable Class Library as the example project.
Ensure the NuGet.exe file in .nuget folder is latest.
Default values come from AssemblyInfo.cs, so clean that up.
Add a NuGet package reference if you do not reference any, preferably something simple like JSON.NET. Often, PCL projects have no external dependencies, in which case no NuGet refs and without any NuGet refs, the required MSBuild config won't get set properly, so we need to add a 'dummy'.
Enable NuGet Package Restore.
Edit the NuGet.targets file and ensure BuildPackage is true.
<!-- Property that enables building a package from a project -->
<BuildPackage Condition=" '$(BuildPackage)' == '' ">true</BuildPackage>
Edit your .csproj file and add this to the first, default PropertyGroup
<BuildPackage>true</BuildPackage>
Rebuild your project and then search in the Output for nupkg and confirm creation and location of the package file.
Remove the dummy NuGet package reference and build again and check the Output.
To further customize the package creation, you can stick a MyProjectName.nuspec file next to your .csproj file.
See http://docs.nuget.org/docs/reference/nuspec-reference for more on the NuSpec format. You can also pull one from an existing package (its just a zip file) and have a nose around, see how it was done.
Add a post-build event like this:
$(SolutionDir)\.nuget\nuget.exe pack "$(MSBuildProjectFullPath)" -p Configuration=Release -o "$(MSBuildProjectDirectory)\bin\Release" -symbols"
And download and place nuget.exe in the .nuget folder alongside your solution file.
You can use nuget update -self to keep the .exe fresh.
Note
nuget.exe pack has a bug currently where it'll see a packages.config file and try to look for the packages it mentions in your solution but it fails to find them if the packages folder is in a strange place, e.g. if your solution file isn't a level up from the project.
To workaround this, add another post build event to copy the packages folder into the project folder.
The repositorypath config setting seems to do nothing for me.
See GitHub reports:
https://github.com/NuGet/Home/issues/5316
So funny. I was having problems with my usual way of auto-building a package on build when I arrived at this new way. So I looked for a suitable SO question to answer with my new post-build method when I came across my own question here!

Including a batch file with VSIX

I'm trying to create a Visual Studio plugin, it's a menu item that executes batch files. I have no idea how to include the batch files (or any other additional files) with the VSIX when publishing so that they are available to all users that install the extension.
In solution explorer right click on the batch file (in this case I called it BatchFile.cmd) and choose 'Properties'
In the properties window change:
Build Action: Content
Include in VSIX: True
When the solution is built in release mode it creates a VSIX file in the bin/Release folder. This is the package and it contains all the assets required. When the package is installed on another machine, the batch file is included in the install location and can be referenced using:
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "BatchFile.cmd"
You can just include the batch file as content in your project, and use GetAssembly() to find the location of your adin dll at runtime

How to "unignore" Visual Studio Web Site *.refresh files when you have [Bb]in/*

I'm using the standard Visual Studio .gitignore at
https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
Part of that gitignore is to ignore the bin folders, but this is a problem, because I need to include bin/*.refresh files for visual studio web site projects.
When one has a (local file) web site project in: C:\Projects\MyprojectA\MyProjectWeb then any references to libraries are stored as "hint files" in the C:\Projects\MyprojectA\MyprojectWeb\bin folder as *.refresh.
So if you reference (a non framework DLL) AjaxControlToolkit.dll, so in the bin folder, you end up with AjaxControlToolkit.dll and AjaxControlToolkit.dll.refresh. The content of the file indicates the path of where to find that DLL. (Let's ignore the potential pathing problems when the repo is cloned, because we're checking in the DLLs into a _lib folder that's also checked into the repo)
How does one "unignore" the *.refresh files found within Visual Studio Web Site project bin folders so that they are included with clones of the repo?
How about using this VS feature?:
Use the exclamation mark.
**/[Bb]in/*
!**/[Bb]in/*.refresh
Once folders are excluded they can't be un-excluded. Do it this way to include sub-folders like roslyn.
replace
[Bb]in/
with
**/[Bb]in/**/*.*
!**/[Bb]in/**/*.refresh
Tiny expansion to Alex' answer, the 'Add Ignored File' button might be hidden under the 'Git' submenu.
'Add Ignored File to Source Control' button

Resources