Add props file properties/variables to csproj hint path - c#

I have added .props file and included it in .nuspec file.
In my .props file i have added new properties/elements in PropertyGroup.
After installing my nuget package, .props file is importing successfully in .csproj file. But how can I include/add props files properties/variables in HintPath (not manually).

Using HintPath & .nuspec for your nugets is an indicator of legacy approach, consider PackageReference & SDK style csproj instead, there is no hint path at all, they are all automatic.
Legacy of Hint Path
Hint path usually used as an item metadata for Reference items for nuget-installed assemblies. Legacy project format been developed when nuget was an external tool (now it is part of .Net SDK). At that time the approach was to have packages.config (you no longer need it) with the list of nugets installed to the project, and while package been installed it have to appear to the rest of .net tools as a regular sideloaded set of assemblies, this is why DLL files are been restored to "packages" folder (this no longer happens), and Reference items are been added to the project with a HintPath having relative path to this "packages" folder. This includes whole graph of references, so if PackageA uses PackageB then both are deployed to "packages" folder and both produces Reference item on all libraries from every package. This way legacy tools used to bring package management to existing ecosystem. For a new PacakgeReference approach you only have to specify top-level package, all transient references will be processed automatically on a restore & build time.
Custom Targets
Since you are mentioning you have props file in your nuspec, let me clarify how now it can be achievend in SDK style csproj in a package that your are publishing (there is no nuspec, all nuspec data is now inside csproj):
<ItemGroup>
<None Include="your_custom.props_or_targets">
<Pack>true</Pack>
<PackagePath>build</PackagePath>
</None>
</ItemGroup>
So, destination path is specified in PackagePath item metadata and it should be build to denote that this is auto-installable targets.
Now in legacy approach when installing package like this, a consumer project automatically have "Import" node to explicitly bring this targets to the project. Now in new SDK approach, if you import package like this with PackageReference, you will not find Import node - it is actually implicitly assumed, so if package under question have targets & props in build folder - all of them will be automatically imported in a build time (not in design time).
PackageReference
<ItemGroup>
<PackageReference Include="YourPackage" Version="3.6.0" />
</ItemGroup>
So if you consume project like this, this is enough to consume Properties that you bring with your custom props inside this package. Feel free to use them as usual an hopefully you no longer need HintPath at all.

Related

How do I include dll as reference in nuget that also gets copied as reference when nuget added to project

We are trying to control versions of nugets being used by hosting them on our own Artifactory and not on nuget.org while trying to package multiple nugets into one.
Example for this is Aspose.
I want to create a new library called AsposeTools that has our own helper functions.
AsposeTools references: Aspose.Cells and Aspose.PDF.
When I install AsposeTools in my project, I want to see AsposeTools, Aspose.Cells and Aspose.PDF so that I can call to use both my helper functions and the actual Aspose functions.
But I want Apose.Cells and Aspose.PDF to be "installed" by AsposeTools not dependencies that get copied down from our artifactory or nuget.org. The reason being cause then we need to maintain version of cells and pdf in both our artifactory and what's being used in tools.
How can I tell the dependency to install from within the nuget it exists instead of a nuget source.
I've tried creating a libs folder within AsposeTools and added the extra dlls to that folder and added them as references. I then tried all the different options for build actions with Copy to Output Directory set to always. The best I could get is that, telling by file size, AsposeTools has the extra dlls included, but I cant actually refence them in code, only my helper functions. The Aspose.Cells and Aspose.PDF are not actually placed in the projects references
EDIT: I use .csproj currently to build the nuget
If my comment's guess is right, you can just set these Apose.Cells.dll and Aspose.PDF.dll as assembly reference so that it will not install them as nuget packages from nuget.org.
Note: it will miss any dependencies of the nuget packages and if you want, you can use the same way to add them automatically.
1) click these nuget packages on the Dependencies -->Properties and then set their Private Asserts to All.
Then, right-click on the project-->Unload project and then click reload Project to enable the settings.
2) enter the xxx.csproj file of the project and then add these:
<PropertyGroup>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<None Include="$(OutputPath)Aspose.Cells.dll" Pack="true" PackagePath="lib\$(TargetFramework)"></None>
<None Include="$(OutputPath)Aspose.PDF.dll" Pack="true" PackagePath="lib\$(TargetFramework)"></None>
// you can add any dependency dlls of the output folder in this way as you want
</ItemGroup>
3) repack your project and when you install the new version, you should first clean nuget caches or just delete caches files under C:\Users\xxx(current user)\.nuget\packages.
When you install the new AsposeTools package, it will not install the other two packages as nuget dependencies from nuget.org. And they are only referenced by the main project only as Assembly reference and also copied into output folder.
ConsoleApp2 is the new main project, and I have installed the new version of AsposeTools package into my project. And this is the effect:

Custom Nuget package shows missing dependency error

I have two class libraries in a single solution (.NET Core). One of them (cl1) is a main library and it depends on another library (cl2). I have added a .nuspec file with the required metadata only (no dependencies, no files) for the cl1 project in the project folder (same location of .csproj file) and I have set GeneratePackageOnBuild propery to true.
Whenever I am building the class library (cl1), the .nupkg is created automatically in the debug/release folder.
When I check the generated .nupkg file, I am see two strange things:
The generated .nuspec file is different than what I have added in the project folder
cl2 is mentioned as a dependency in the newely generated .nuspec file, but the DLL for cl2 is not included in the lib folder of the .nupkg. So, whenever I consume this package in another solution, I am getting the error No packages exist with this id in source(s) for the cl2.
I have surfed in internet, but was not able to find a proper solution for the above error.
And I have added a .nuspec file [...] in the project folder(same location of .csproj file)
You have to specify the path to your own NuSpec file in the .csproj using the NuspecFile tag, otherwise it will be ignored and the package will be created with the metadata from the .csproj file instead, see reference. You need to use either a relative or an absolute path to the file, for example:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<NuspecFile>cl1.nuspec</NuspecFile>
</PropertyGroup>
</Project>
The generated .nuspec file is different than what I have added in the project folder
As already stated, your NuSpec file is probably not included. However, even if it is, there can be differences, because some information, e.g. source file locations are unnecessary and the target locations are in most cases given by the internal package file structure itself, so it is not there because it is redundant.
cl2 is mentioned as a dependency in the newely generated .nuspec file, but the dll for the cl2 is not included in the lib folder of the .nupkg. So, whenever I consume this nupkg in other solution, I am getting error " No packages exist with this id in source(s)" for the cl2.
Dependencies are meant for packages. So when NuGet restores the package it searches for other packages that this package depends on, here cl2, but there is none, hence the error. When packing a project, referenced projects are not included in the package. That is an open issue and there are workarounds that you can try.
The most reliable, but inconvenient solutions are to avoid the issue at all.
Only use a single project, everything will be included in the package
Pack each project on its own and use the generated package instead of the referenced project

Create multi-target nuget package from several csproj contained in different folders from nuspec file

I am trying to create a nuget package for a library which exists in 2 versions, each of them targeting two different .NET versions.
Here is my folder structure:
As you can see my nuspec file is one directory above my csproj (which are in the /net452 and /netcoreapp2.0 folders).
I am using the following command line to build my nuget package:
nuget pack .\my.nuspec -properties Configuration=Release -Build
The issue is that the build can not be achieved because the csproj files are not in the same folder as the nuspec file.
Please note that the packaging works fine when both projects have been priorly manually built.
I'm very new to this process and I'm not sure what I should do in that scenario, is there a simple way to reference the 2 csproj from the nuspec or - assuming I want to keep this folder structure - would I need to make a script that builds the projects first and then invoke nuget pack?
EDIT: To clarify my issue, I do have two different csproj files, contained respectively in /net452 and /netcoreapp2.0, and they compile the source code in their respective directory to produce two different dll. These two dll are then referenced in my nuspec file in order to offer my package in net452 or netcoreapp2.0 with the following syntax:
<files>
<file src="lib\**" target="lib" />
</files>
Note: after I manually compiled my two projects, the directory looks like this (note the lib folder that contains a net452 and netcoreapp2.0 folder with the appropriate version of my dll).
Not sure if understood correctly - you have one library and want to build it in two versions (net452 and netcore).
Did you try adding following items to *.csproj?
<PropertyGroup>
<TargetFrameworks>net45;netcoreapp2.0</TargetFrameworks>
</PropertyGroup>
Then you can have on project with two outputs from build

How to tell nuget to add package resource files as links, and not copy them into project directory

Intro (how to pack resources into a nuget package)
To pack some resource files into a nuget package, what one would normally do, is the following.
Put all the resource files into the content\ directory of a nuget package. This would be specified by the following line in a .nuspec file:
<files>
<file src="Project\bin\Release\script.js" target="content\js\script.js" />
<files>
Now, when this nuget package gets installed into AnotherProject, the following file structure emerges:
Solution.sln
packages\Project.1.0.0\content\js\script.js // the original resource file
AnotherProject\js\script.js // a physical copy
AnotherProject\AnotherProject.csproj // <Content /> tag (see below)
During package installation, AnotherProject.csproj was injected with tag:
<Content Include="js\script.js" />
and this is for the physical copy of the original resource (which is under packages\ directory).
The actual problem (how to pack resources into a nuget package as link)
My aim is not to have the physical copy of a resource file in the AnotherProject directory but rather a "link" to the original resource under packages\ directory. In the csproj, this should look like this:
<Content Include="packages\Project.1.0.0\content\js\script.js">
<Link>js\script.js</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Brute force solution that I would rather avoid
Now, one "do it the hard way" workaround I can think of is:
not putting resource files under content\ so they do not get added automatically,
writing Install.ps1 script that would hack the csproj file structure and add the necessary XML piece manually,
This, however, has the following drawbacks:
all my nuget packages need the same script piece in their Install.ps1,
when installing my packages, there would be a nasty "project reload prompt" in Visual Studio.
Since NuGet currently does not support this out of the box your options are either to use PowerShell or to use a custom MSBuild target.
PowerShell
Leave your resources outside of the Content directory in your NuGet package (as you already suggested).
Add the file link using PowerShell in the install.ps1.
You should be able to avoid the project reload prompt if you use the Visual Studio object model (EnvDTE). I would take a look at Project.ProjectItems.AddFromFile(...) to see if that works for you.
MSBuild target
NuGet supports adding an import statement into a project that points to an MSBuild .props and/or .targets file. So you could put your resources into the tools directory of your NuGet package and reference them from a custom MSBuild .props/.targets file.
Typically the custom .props and .targets are used to customise the build process. However they are just MSBuild project files so you could add items for your resources into these project files.
Note that .props are imported at the start of the project file when a NuGet package is installed, whilst .targets are imported at the end of the project.
Customising NuGet
Another option, which would take more work, would be to modify NuGet to support what you want to do.

Differences between nuget-packing a csproj vs. nuspec

Recently, I started to pack nuget packages out of my several projects. First I started with the Package Explorer application. It is a nice tool, but it's less useful if you do continuous integration. Then I looked into specifying the nuspec template file, and passing changing data, e.g. version number, as command line arguments. Later, I wondered how to define the nuget package dependencies. As it turns out, the nuget.exe already does this based on the package.config if you specify a csproj. Moreover, it extracts relevant data like Author, Version, Copyright right from the assembly info. What I'm missing right now is the ability to specify a licenseUrl in the command line. But I wanted the question to be more generic. And so I'm asking:
What is the prefered way to pack nuget packages?
Here's a little-known fact: you can combine both!
Target a csproj file, and make sure there's a nuspec file in the same directory with the same name as the csproj file. NuGet will merge the two during package creation.
So in short: target <ProjectName>.csproj, optionally add a corresponding tokenized <ProjectName>.nuspec file to be used as metadata by NuGet.exe.
It saves you from managing output location, dependencies, version, and other stuff that can be derived from the project.
With a .csproj for Visual Studio 2017, you don't need a .nuspec file. You can actually add the values directly to your csproj and it will pick them up.
Right click the project in Visual Studio, Edit xxxxx.csproj. Notepad works fine too.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>1.0.1</Version>
<authors>Subtracts</authors>
<TargetFrameworks>netstandard1.6;net452</TargetFrameworks>
<AssemblyName>Checkout.net</AssemblyName>
<PackageId>Checkout.net</PackageId>
...
</Project>
p.s. Since I don't have sufficient reputation to comment, I am leaving an answer instead of a comment on Xavier's answer. :)
For simple packages you can directly create the packages off .csproj or .vbproj. But for more advance packages, especially when you need to pull in custom files into your package, you need to use .nuspec. I usually start off with the csproj and move to nuspec as needed. You can always get the nuspec using the command nuget spec on the csproj.
https://docs.nuget.org/create/creating-and-publishing-a-package
You can specify any of the properties including licenseUrl using the Properties parameter to nuget pack
nuget pack -properties licenseUrl=http://blah
With .NET Core as of February 2018 you'll need to supply a .nuspec file for any more than the basic spec file properties.
But the dotnet pack command will not use the .nuspec file unless you add <NuspecFile>relative path to nuspec</NuspecFile> to the .csproj file.
See https://github.com/dotnet/cli/issues/2170
Most packages can now be made without a .nuspec file. The thing to watch is the dependencies. You may need to add a PrivateAssets element to some that are tools, like msbump and um, SpecFlow maybe.
<PackageReference Include="msbump" Version="2.3.2">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
This stops this package dependency "flowing" to the dependencies of your package.
Also worth reading about specifying versions in the most flexible way.
https://learn.microsoft.com/en-us/nuget/consume-packages/dependency-resolution#floating-versions
And range syntax.
https://learn.microsoft.com/en-us/nuget/reference/package-versioning#references-in-project-files-packagereference

Categories