I am creating a nuget package where part of the result of installing the package is to modify my web.release.config.
I have no problem inserting elements into this file with my web.release.config.install.xdt, but I need to keep the xdt:Transform and xdt:Locator attributes on the elements I am inserting because these transforms will need to be run when the application is built for deployment.
So for instance when installing the nuget package I would like to see:
<add key="serilog:using" value="Serilog.Sinks.Seq" xdt:Transform="InsertIfMissing" xdt:Locator="Match(key)" />
show up in the web.release.config including the xdt:Transform and xdt:Locator attributes.
Is it possible to do this?
I don't believe what you are trying to do is supported by either msbuild or SlowCheetah. Most NuGet package owners dont know enough about their customers implementation to set values into environment specific configs. Additionally the transform tools where not written with NuGet in mind as they was built to serve a different need. Sorry for the bad news.
You may be able to use an init.ps1 powershell script to get this done (NuGet will run this script the first time the package is installed in the solution) but it will be less than clean.
Related
I am learning how to use Visual Studio and publish/consume NuGet packages. After following these tutorials:
https://learn.microsoft.com/en-us/nuget/consume-packages/overview-and-workflow
I can create a simple NuGet package and publish/build it fine, as well as find the resulting .csproj project file.
One task I've been assigned is creating a Visual Studios Solution File that will automatically download a NuGet package, but I haven't seen this talked about in the NuGet documentation yet.
How can I to create a Solution File ( or maybe a project file?) for Visual Studio 2019, such that any user can consume (run?) this file with their project, to have NuGet project automatically downloaded to their Visual Studio project?
OP:
I can create a simple NuGet package and publish/build it fine, as well as find the resulting .csproj project file.
...and OP:
I know you can search for a NuGet package through the visual studio interface to download. But If I have a package hosted in a private artifactory repo, wondering if there are any other ways in visual studio to download it
So I am assuming you have already published the NuGet package, referenced it in your projects via Manage NuGet Packages for solution... at least once and committed the results to source control for others in your team to use. But the problem is that you would some form of automatic workflow so that when your team members open the solution, the packages are automatically restored even though they are on your private NuGet server wherever that may be, something your team members environment is not currently configured for. This is not a problem.
So there's a two ways this can be done:
Specifying additional NuGet package sources in Package Manager Settings in Visual Studio
Modifying NuGet behaviour at solution, user or machine scope
1.0 Choices
1.1 Manually configure NuGet via Package Manager settings in Visual Studio
#1, is arguably the easiest as is done via VS's user interface. Unfortunately it does require team members to manually apply these settings which is something you wanted to avoid in the first place. Additionally is is essentially user-scope so will affect any solution you open in Visual Studio leading to possible problems if multiple solutions are fighting over custom configuration:
Also be warned, if like me you are working-from-home and have added your employer's NuGet server to the above, don't be surprised that the build suddenly stops working, specifically NuGet restore. I often find myself having to re-authenticate with my employer account or temporally disabling the custom NuGet source.
1.2 Configure NuGet via NuGet.config files present in source control
In this option you configure NuGet via nuget.config files, something that can be added to source control. Why is that important? Well when your team grabs the latest code say via Git, they'll also find a brand spanking new nuget.config in the repo's root folder that Visual Studio (and CI servers for that matter) will detect, leading to an automatic solution-specific configuration of NuGet that will add your custom NuGet packages to the restore operation when you go to build your solution. Yay!.
You have complete freedom over where such customisation are applied depending upon scope:
solution
user
machine
MSDN has this to say on nuget.config files:
nuget.config is an XML file containing a top-level node, which then contains the section elements described in this topic. Each section contains zero or more items. See the examples config file. Setting names are case-insensitive, and values can use environment variables.1
...and:
NuGet's behavior is driven by the accumulated settings in one or more NuGet.Config (XML) files that can exist at project-, user-, and computer-wide levels. A global NuGetDefaults.Config file also specifically configures package sources. Settings apply to all commands issued in the CLI, the Package Manager Console, and the Package Manager UI.2
Here's an example nuget.config. Note how I list my custom NuGet package source first (though not entirely necessary) before listing the standard NuGet source. The config file does not have to exist in the same folder as the Visual Studio solution (.sln) file but perhaps in the repo root (see below) so when the solution is built, preference is given to it over any other settings (including what is in VS's user interface):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<clear />
<add key="repositoryPath" value="packages" />
</config>
<packageSources>
<!-- When <clear /> is present, previously defined sources are ignored -->
<!-- Remove this tag or un-comment the nuget.org source below to restore packages from nuget.org -->
<!-- For more info, see https://docs.nuget.org/consume/nuget-config-file -->
<clear />
<add key="Contoso" value="https://mickyd.com/packages/" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<packageRestore>
<add key="enabled" value="True" />
<add key="automatic" value="True" />
</packageRestore>
<activePackageSource>
<add key="All" value="(Aggregate source)" />
</activePackageSource>
</configuration>
Microsoft recommends that you place the nuget.config file (my emphasis):
...in the root of your project repository. This is considered a best practice as it promotes repeatability and ensures that different users have the same NuGet configuration.1
Be sure to check out the rather detailed Example config file on MSDN.3
1 "nuget.config reference", MSDN
2 "Common NuGet configurations", MSDN
3 "Example config file"
I am working with Newtonsoft.Json (a.k.a. Json.net) now and multiple C# solutions need to reference it. Seems the most convenient and widely-used way is to install Newtonsoft.Json with NuGet package manager. But I find that the package is installed in the solution root directory (anyway, the installation is based on a given solution) and its size cannot just be neglected (a bit over 10M), so I wonder if there is an elegant way to share this package among different C# solutions.
I searched Google and found few satisfying results (maybe it's because I didn't express my requirement properly); the only sound answer is to create a .nuget folder both in the directory and in the solution and fill it with a NuGet.config file, as follows:
Create a .nuget folder in the root of the solution (by entering ".nuget.", actually)
Inside that folder, create a file NuGet.config.
In Visual Studio 2015, right click on the solution and add a new solution directory called “.nuget”
Right click on that folder and select to add an existing file and select the NuGet.config file created in (2).
Add content like this inside the NuGet.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<solution>
<add key="disableSourceControlIntegration" value="true" />
</solution>
<config>
<add key="repositoryPath" value="E:\JsonExamples\C#Examples\UseJsonInCSharp\packages" />
</config>
</configuration>
Restart Visual Studio 2015.
But that didn't work because the using directive
using Newtonsoft.Json;
is still not recognized! Maybe there are something else that must be done, which isn't known to me but is common sense to veterans? Or perhaps this is because the version of the Newtonsoft.Json is too new for this to work? Can somebody help me? thanks a lot!
One more word: I'm currently using VS 2017, but I only found answers related to VS 2015, so I wonder the previous approach, if somehow works on VS 2015, will ever work for VS 2017.
Lets first clarify some things about NuGet and references in projects:
The job of references in project is to tell what external code this projects must look into - you can NOT go around this, you have to make a reference to Newtonsoft.Json in every project you want to use it.
The job of NuGet is to download/restore the nuget in some folder - the default "dumb" setting for old pre NuGet 4 versions is to make a seperate packages folder in every solution. Lets Focus on how to make this smarter.
Option 1 (Recommended) - Migrate everything to PackageReference
It is available since NuGet 4 in VS 2017+ (i recommend at least VS 2017 15.7+ which got wizard for automatic migration from older nuget versions). This is the most clean way of referencing NuGets since PackageReference in project does not hardcode NuGet download location. Instead it leaves this decision to local NuGet settings. By Default it is set to "%USERPROFILE%\.nuget\packages". No nuget package is duplicated, it acts as global cache for this computer. To force all new project to use PackageReference by default you must modify NuGet.config, here is how: Defaulting Package Management to PackageReference
Option 2 - specify common NuGet location for all project in the same repository
NuGet config settings are loaded per Solution. Having a common config file for NuGet is recommended even if you use PackageReference since download location is just one of many settings you might want to centrally manage for all Solutions (the other popular one is a setting which external NuGet repositories you want to use). NuGet download location setting is ignored by new PackageReference so it is safe to use it in mix scenario. VERY IMPORTANT, projects using this old NuGet use hardcoded reference to NuGet folder, so everytime you change this NuGet location setting you have to manually fix all NuGet references in your every project (by editing .csproj file manually or be deleting and re-adding NuGets), so chose wisely and do not change.
Details on how to correctly set global NuGet.config:
So first let me explain how shared NuGet.config settings work. NuGet scans all NuGet.config files from solution location up the hierarchy to root drive (it also check all .nuget folders). If multiple config files are detected it takes the one closest to solution. So for example you have "C:\Code\Repository1\Project1\Solution1.sln". If you want to have common NuGet settings for every solution in Repository1 put config file to a location like this "C:\Code\Repository1\NuGet.config". Also make sure this is the only config file inside whole Repository1 folder. Next step is to decide where to download all packages, for example "C:\Code\Repository1\NuGetPackages". To make everything work dynamically on all computers put relative path inside NuGet.config like this:
add key="repositoryPath" value="NuGetPackages"
Below is my current nuget.config that is working in VS2013.
Im looking to move over to VS2017 but i need to make changes to the nuget.config file in order to do so.
Is there anyway i can write my nuget.config so that it can work in either VS2013 or VS2017?
The reason i ask is because not all developers are working on the same version of visual studio, and when i checkin the changes required to work with nuget it will break for those loading the solution in VS2013.
<!-- VS2013 -->
<?xml version="1.0" encoding="utf-8"?>
<settings>
<repositoryPath>..\lib</repositoryPath>
</settings>
<!-- VS2017 -->
<configuration>
<config>
<add key="repositoryPath" value="..\lib" />
</config>
<packageRestore>
<add key="enabled" value="True" />
</packageRestore>
</configuration>
My suggestion is update the nuget version that you have to the latest one, then add a nuget repository in all visual studios in your teams to point to the same folder location.
The only thing that you need to understand at least is if one of your developers(Team A) using 2013 version removes a package there should not be any problem for the developer(Team B) using 2017 because when Nuget recognizes after you get the latest version of the repository folder, that a folder is not present on the package folder because it recognizes based on the package.config which are installed and which not, then you should get the dependency again an submit it as new change to your source control tool, after that the second project will point to the correct references, and your Team A will not have it included as part of their dependencies.
Second approach: you can go to your vs2013 projects and update all references to the new repository using the latest configuration(NuGet.Config file) , that should work
Here are the steps I follow when I need to configure NuGet from scratch
NUGET CONFIGURATION:
The approach is to unify and reduce duplicated dependencies of all projects and place them in a common place where every project can make use of it. The advantage is not just unifying the dependencies; it also brings a reduction of space on the TFS and preserves a hierarchical structure for automatic builds as well.
STEP 1: Common folder for Nuget Packages
First you need to create the Common folder at the root level of all your projects with a Packages folder inside. Feel free to copy manually if you want all .NuGet packages that you have in other projects to the latter folder or leave it to the Visual Studio when you include a new dependency.
Common will work as a Nuget repository, but on this case as a local Nuget. repository. Your Visual Studio configuration should know that. Follow the next step
Then you need to create with the plus button a new Seed Repository (your local). Below I named: Packages. After that browse the folder for your new packages. Then click ok
Now you can go to your Project and make a right click to include a new dependency
Then go to package source and select Packages and you will see all the packages available on the Packages folder that should be empty the first time
The idea here is to download the packages we need from the Packages folder instead from the Nuget repository, if the package don’t exist then change to the search to nuget.org option and download the package from there. The effect should be the same
STEP 2: Prepare the configuration files
Here we want to avoid that Nuget to save packages inside “packages” folder at the root of our project, which is the default behavior of nuget when you download a package.
Rather we want to download the package to Common/Package folder. In order to do that, we need to add a Nuget.config file in our structure. Create a NuGet.Config file inside the root of your project.
TFS View
Inside NuGet.Config type
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositoryPath" value="$\..\Common\Packages" />
</config>
</configuration>
For the repositoryPath setting, you can specify an absolute path or relative path (recommended) using the $ token. The $ token based on where the NuGet.Config is located (The $ token is actually relative to one level below the location of the NuGet.Config). So, if I have \ Team Project\NuGet.Config and I want \Team Project\Common\Packages I would need to specify $..\Common\Packages as the value.
STEP 3: Final step.
Start downloading the packages and make sure you check in all changes.
If you have a package folder at the root of your project you can get rid of it in case you want to set the correct references to the new folder. Feel free to delete it if that is what you want. But if you want to keep the legacy code pointing to the package and start using the new Common folder for future packages, then you need to keep both.
Below I fixed all references, there is no “package” folder and still can include new packages.
Enjoy!!!
I'm sorry to tell you that this is not possible. This was a breaking change to accommodate .Net Core and other versions of VS (i.e., VS for Mac). I stumbled upon this info when looking into vs 2017 RC and .net core tools preview.
I hired a contractor to do some coding for me. He setup nuget.config in the solution folder with the following repository path:
<configuration>
<solution>
<add key="disableSourceControlIntegration"
value="true" />
</solution>
<config>
<add key="repositoryPath"
value="../lib" />
</config>
</configuration>
And I'm not too happy about his decision: this will place the nuget package folder outside the solution folder. I can easily change the repository path, simply by setting:
value="../<mySolutionFolder>/lib" />
However when I do this a curious thing happens: every single reference that I use in my solution is now broken. And nothing that I change in the .csproj files or other *.config files will allow my projects to find their references.
The only workaround is to re-create each project in my solution by starting from scratch, and add->existing items, etc. and reference->manage nuget packages, and install every reference again.
I have many projects in my solution and performing this for every one is understandably time consuming.
I would like to know if there is an easy way?
It seems like there should be a way for Nuget and VS to play nicely so that I can easily move the repository folder to a different path location.
One way to fix the reference paths is to use the Package Manager Console.
From the Package Manager Console you can run the following command to reinstall the NuGet packages which will fix the hint paths for the references.
Update-Package -reinstall
This will reinstall all NuGet packages in the solution. I am assuming you have the code under source control so you can see what changes are made to the projects if you need to revert them after this reinstall.
There is more documentation on reinstalling NuGet packages on the NuGet documentation site.
Another way to fix this is to do a find and replace in the .csproj files to fix the hint path.
I encountered this problem when I moved the actual folders around in my solution. I usually do a find/replace with VS Code looking for >..\packages\ and replace it with >..\..\packages\. This time I did the following:
Perform Update-Package -Reinstall
this worked for everything with hint paths
does not work when your project uses NuGet packages to build your project because there are custom MSBuild statements that need to be manually fixed, see next step.
Edit the .csproj files manually that do not build, in my example:
<Import Project="..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.8\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props" Condition="Exists('..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.8\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" />
<Import Project="..\..\packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props" Condition="Exists('..\..\packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props')" />
Notice that there are 2 condition statements in the <Import> that use relative pathing to ..\..\packages.
Hopefully these steps will help someone else.
Package.config is used for put file somewhere else from the folder, it help best to not upload package unusually when you add something in your project through Nuget.
Try to copy the package to that folder (new path you set) or simply close the project, open it again and click on Restore after going to Manage project reference.
After trying all solutions posted here I could not escape one primary issue: references to non nuget items, such as System and System.Core remained invalid (yellow triangle listed next to them). Removing them and adding them did not make them valid again. Further (as we all know) Visual Studio is terrible and giving reasons for why a reference is considered invalid.
So while Matt's solution does indeed relocate the nuget package folder, the solution in not left in a working state. Further, updating hint paths did not help because those are specific to the nuget packages. I cannot explain why basic references suchas System also become invalid. Perhaps someone reading this a year from now can leave a message with an explanation.
What I ended up doing is rebuilding my entire project without a nuget.config file (I deleted it). This causes nuget to use all defaults. Downloaded packages get stored in \\<solution_folder>\packages\. After the solution was working again, I added back the nuget.config file but with the following removed:
<config>
<add key="repositoryPath"
value="../lib" />
</config>
...and removing that section causes nuget to rely on default behavior which turns out to be exactly what I wanted (installing packages to \packages, etc).
If anyone else is about to undertake this laborious effort, I found this SO solution helpful for moving folders and files from the old solution to the new one.
I managed to do this to my own solution without realising how (and ended up with a packages folder at the *.sln level and another one at The level below that) - but I'm pretty sure now that this all has to do with migrating from using a packages config file, to the new method of using package references. This can occur if you use a newer version of visual studio (which is possibly what your contractor did) or via a button/commend in NuGet, or via a right-click context menu.
One of the things that happens is the creation of a 'global' packages folder (the one at .sln level) which is meant to save your space since it means you can have multiple solutions using the same package without having huge duplicate package folders repeated in every solution.
I found this out when I was merging The text is two csproj files and needed to Google: import project difference to package reference
See https://learn.microsoft.com/en-us/nuget/reference/migrate-packages-config-to-package-reference
I have put a library that my team uses into a nuget package that is deployed from TeamCity into a network folder. I cannot debug into this code though! SymbolSource is one solution I have read about but I would much rather find some way to have access to the .pdb/source files directly from TeamCity. Does anyone know how to do this?
Edit. When I check 'Include Symbols and Source' in the Nuget Pack build step, TeamCity creates a .Symbol.nupkg in addition to the .nupkg file in the network folder. The .Symbol.nupkg contains the src and the .pdb file.
Edit. I unchecked 'Include Symbols and Source' on TeamCity and added the following to my nuspec file:
<files>
<file src="..\MyLibrary\bin\release\MyLibrary.dll" target="lib\net40" />
<file src="..\MyLibrary\bin\release\MyLibrary.pdb" target="lib\net40" />
<file src="..\MyLibrary\*.cs" target="src" />
<file src="..\MyLibrary\**\*.cs" target="src" />
</files>
This added the dll, the pdb, and the source files for my library in the nuget package and didn't generate a .Symbols file which I think is only needed for symbol servers.
Traditional method
Put the pdb in the NuGet package alongside the dll.
Add the source code to the Debug Source Files for the solution that references the package.
This means you'll be able to step through code and view exceptions, but you might have to find a file on disk and open it before you can set a breakpoint. Obviously you need to be careful that the source is at the right revision.
More detail on step
If you're currently packaging without a Nuspec, you'll need to create a Nuspec, then add the pdb to the list of files in the lib folder "NuGet spec" may be a useful command for generating the initial spec as defined in NuGet docs. Then ensure the Team City Nuget Pack step is referencing your new nuspec.
More detail on step 2
When you have a solution open, right click on Solution, select Properties...Common Properties...Debug Source Files, and add the root source directory for the relevant binary reference. Or see MSDN.
Note, you can't open the solution properties while debugging.
Still not hitting breakpoints?
Try disabling this from Tools->Options:
Modern way for public or private repos
To ensure the exact version of the source is available, embed it at build time.
From Visual Studio 2017 15.5+ you can add the EmbedAllSources property:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<EmbedAllSources>true</EmbedAllSources>
Modern way for public repos
To keep your nuget and library size small, you can use the sourcelink package.
It generates a pdb that directs the debugger to the correct version of the file from your VCS provider (e.g. GitHub, BitBucket).
The latest version of dotPeek (free!) can act as a symbol server and generate pdb files on the fly. This has allowed me to debug into the dlls that are served via teamcity.
Download it here:
http://blog.jetbrains.com/dotnet/2014/04/09/introducing-dotpeek-1-2-early-access-program/
Instructions on how to set it up here.
https://web.archive.org/web/20160220163146/http://confluence.jetbrains.com/display/NETCOM/dotPeek+Symbol+Server+and+PDB+Generation
You could of course set-up & configure your own symbol server, but it's probably easiest to...
download and install Inedo's ProGet
enable symbol serving on the target feed
publish packages from TeamCity to the ProGet feed
use ProGet as your primary feed source (as it can aggregate multiple feeds including nuget.org)
All of this can be done with the free edition of ProGet.
disclaimer -- my day job is at Inedo
In your .nuspec (directly under <package>):
<files>
<file src="bin\$configuration$\$id$.pdb" target="lib\net451\" />
</files>
(change net451 to the platform you're compiling for)
If you have the source code for the package, then the foolproof (but possibly laborious) method is:
Add the source code for the package to your solution (right click Solution -> Add Existing Project)
Go through all of your projects in the solution and remove the NuGet reference to the library (i.e. open the References folder under each project and delete the reference to the package.) Then, add a reference to the NuGet package project in your solution. (i.e. Right click References, add Reference, choose Projects and tick the box for the project)
I had to do it this way when I the method I wanted to debug inside the NuGet package was called by the framework and not by my code, thus I couldn't step into it. (In my case, the method was an ASP.NET DelegatingHandler).
Once you're done you'll want to undo all your changes via source control so that the NuGet package is referenced correctly.
I've found a super simple way to do this, which I have blogged about here:
https://mattfrear.com/2017/11/29/speed-up-development-in-a-nuget-package-centric-solution/
This only works if you're using the new .NET Core style .csproj with <PackageReference> (on either .NET Core or .NET Framework).
This again assumes you have access to the source code of the NuGet package.
Build and compile the NuGet package on your local machine
Copy the .dll you've just compiled into your local NuGet packages feed folder (On my machine, this is C:\Users\matt\.nuget\packages\), overwriting the existing NuGet package .dll.
That's it! You should be able to step into the package while debugging. No messing around with .pdbs or source servers. This has greatly sped up my development cycle.
Since this question was originally posted, Jetbrains have written an entire blog post on how to accomplish this. The steps can be summarised as:
Install Debugging Tools for Windows on the agents.
Install & Enable the Symbol Server plugin.
Add Symbol Files Indexer build feature to your build configurations.
Ensure PDB files are output as an artefact.
Configure Visual Studio to use TeamCity as source server.
If you are using Nuget Package build steps, you can check 'Include Symbols and Source' to output a .symbol.nupkg which contains the PDBs. Depending on whether the Symbol Files Indexer is smart enough to look inside this file or not, you may need to change the file extension for things to work.
The full details are given here:
https://blog.jetbrains.com/teamcity/2015/02/setting-up-teamcity-as-symbol-and-source-server/
This is what I have found to work, but all the steps are probably not required...
Note: this doesn't allow you to debug both, only either the nuget
package or the solution in which it is installed.
Run Visual Studio as Administrator
Open and Start the host application (the one in which you installed the Nuget package) without debugging (Ctrl + F5)
In the Nuget package solution, ensure that Tools > Options > Debugging > General > "Require source files to exactly match the original version" is NOT checked.
Ensure that "Enable just my code" is NOT checked
Add a new folder in Tools > Options > Debugging > Symbols pointing to the source directory of the Nuget package. (You literally enter the folder path , see image below)
Click Debug > Attach to Process...
Find iisexpress (there may be multiple, it won't do any harm attaching to all)
If your code is in a public Git repository, or, at least in your network, is accessible without authentication, then GitLink would be an option:
https://github.com/GitTools/GitLink
GitLink makes symbol servers obsolete by changing the PDB to point to the Git server. But, as said before, this makes it necessary for the Git repository to be public - until now there's no "proper" way to authenticate when accessing a private repository.
Microsoft has now integrated the SourceLink NuGet package at https://github.com/dotnet/sourcelink/ which allows source code to be downloaded on demand while debugging if the publisher of the NuGet package sets it up.