I'm trying to pack a new version of a custom NuGet package and when I use the pack command I'm getting a .nupkg file which has a version number that doesn't match with the one that I've specified in the .nuspec file.
Example:
nuget pack mypackage.csproj -IncludeReferencedProjects -Prop Configuration=Release
.nuspec file:
<?xml version="1.0"?>
<package >
<metadata>
<id>mypackage</id>
<version>1.0.1</version>
<authors>me</authors>
<owners>me</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>blah</description>
<releaseNotes></releaseNotes>
<copyright>Copyright 2016</copyright>
<tags>tag1 tag2</tags>
<dependencies>
</dependencies>
</metadata>
</package>
I should get a file named mypackage.1.0.1.nupkg, but I'm getting a file named mypackage.1.0.0.nupkg instead
I'm also getting the same result when I try to pack it by using the AssemblyInfo data included in the Properties\AssemblyInfo.cs and declaring the version as a variable in the .nuspec file:
Properties\AssemblyInfo.cs
...
[assembly: AssemblyVersion("1.0.1")]
...
Should I look for another properties in my project to update my NuGet package?
SOLUTION: Ignored the .nuspec file and managed the package versions via .csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net451;net452</TargetFrameworks>
...
<AssemblyVersion>1.2.1</AssemblyVersion>
</Project>
Thanks in advance!
Make sure to change both the Assembly Version and File Version in Project Properties > Application > Assembly Information.
After that make sure you are set to Release mode and build your project.
Execute the Nuget Spec command in your project's folder
Edit the Spec, version should be set to $version$ so as to grab it from your project, remove the lines that need removing, fill the ones with placeholders.
Execute your Nuget Pack command in the same folder and you should be good.
I often forget to build my project so it doesn't update the version.
I fell foul of this recent as well.
You need to use the Properties\AssemblyFileVersion attribute to set the correct value for a nuget package
[assembly: AssemblyFileVersion("1.0.1")]
Well, I've finally managed to update my version by packing using the AssemblyInfo version. It seems like my publishing process for this package is completely ignoring the .nuspec file and gets the version from the last compiled source.
Related
From following question How do I list all installed NuGet packages?
I need to get a list of nuget packages from MSBuild itself.
What I try to do:
<Target Name="test" AfterTargets="ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="#(ReferenceCopyLocalPaths)"/>
</ItemGroup>
<Message Text="Files #(BuildOutputInPackage -> '%(identity)', ', ')" Importance="high"/>
</Target>
Above code return all references whether its nuget or project references dlls. How exactly to return a list of nuget package that currently project *.csproj used?
Format i.e: packageid:Portable.BouncyCastle version = "1.9.0"
I use old classic non-sdk csproj template and .NET 4.8 and <PackageReference> not packages.config files.
Its very bad to read *.csproj and do regex to get a list of <packageReferences. Maybe there's a recommended MSBuild macro to do this like code shown above <Target....
ReferenceCopyLocalPaths is only "Paths to files that should be copied to the local directory." It is not all resolved references.
Yes, don't regex the project file. There is no need. PackageReference is an ItemGroup.
<Target Name="DisplayPackageReference">
<Message Text="#(PackageReference ->'packageid:%(identity) version = "%(version)"', '%0d%0a')" />
</Target>
But note that PackageReference is what the project is asking for and the version can be floating, e.g Version="3.6.*". PackageReference won't give you the package version that the package reference was resolved to.
If you need to know the specific version used, then you may need to install dotnet, use an exec task to run dotnet list "$(MSBuildProjectFile)" package, and parse the command's output.
Very thankful to Jonathan Dodds for his answer above. I combined some approach with his #(PackageReference) idea to get a version of currently referenced nuget package in old classic csproj template. Because a referenced version will not work with #(PackageReference) only. Also dotnet list not worked well in old classic csproj template (non-sdk).
A code below do following:
(Note this approach is not 100% organic, MSBuild should provide a simple target for that):
Get all references that maybe be nuget or non-nuget (DLLs, etc).
Get only references that included inside #(PackageReference). Jonathan Doods approach above.
Get .nuspec file for that package to know exactly what version current *.csproj referenced.
Create a new nuspec file for current project. with a list of dependencies.
You can then call nuget.exe pack ProjectPath.csproj a ProjectName.nupkg nuget will generated.
Use this code inside Directory.Build.targets or within your .csproj file.
<Target Name="GenerateNuspecFile">
<ItemGroup>
<!-- Get all references -->
<MyReference Include="#(ReferenceCopyLocalPaths)" Condition="%(extension) == '.dll'">
<FirstDir>$([System.IO.Directory]::GetParent(%(RelativeDir)))</FirstDir>
<LibDir>$([System.IO.Path]::GetFileNameWithoutExtension(%(MyReference.FirstDir)))</LibDir>
<SecondDir>$(FirstDir)</SecondDir>
<SecondDir Condition="$(LibDir) != 'lib'">$([System.IO.Directory]::GetParent(%(MyReference.FirstDir)))</SecondDir>
<VersionDir>$([System.IO.Directory]::GetParent(%(MyReference.SecondDir)))</VersionDir>
<PackageDir>$([System.IO.Directory]::GetParent(%(MyReference.VersionDir)))</PackageDir>
<PackageID>$([System.IO.Path]::GetFileName(%(MyReference.PackageDir)))</PackageID>
<NuspecFile>%(MyReference.VersionDir)\%(MyReference.PackageID).nuspec</NuspecFile>
</MyReference>
<!-- Get Non nuget references -->
<ExcludedReference Condition="#(MyReference) != ''" Include="#(MyReference -> '%(PackageID)')" Exclude="#(PackageReference -> '%(identity)')"/>
<!-- Get nuget references after exclude non-nuget references -->
<MyPackage Condition="#(MyReference) != ''" Include="#(MyReference -> '%(PackageID)')" Exclude="#(ExcludedReference -> '%(identity)')"/>
<!-- Read Nuspec File -->
<NuspecContent Condition="#(NuspecFile) != ''" Include="%(MyPackage.NuspecFile)">
<Content>$([System.IO.File]::ReadAllText(%(fullpath)))</Content>
<PackageIDRegex><id>(.*?)</id></PackageIDRegex>
<PackageID>$([System.Text.RegularExpressions.Regex]::Match('%(NuspecContent.Content)', '%(NuspecContent.PackageIDRegex)' ))</PackageID>
<PackageID>$([System.String]::Copy('%(NuspecContent.PackageID)').Replace('<id>','').Replace('</id>', '').Trim())</PackageID>
<VersionRegex><version>(.*?)</version></VersionRegex>
<Version>$([System.Text.RegularExpressions.Regex]::Match('%(NuspecContent.Content)', '%(NuspecContent.VersionRegex)' ))</Version>
<Version>$([System.String]::Copy('%(NuspecContent.Version)').Replace('<version>','').Replace('</version>', '').Trim())</Version>
</NuspecContent>
</ItemGroup>
<!-- Generate Nuspec File with dependencies-->
<PropertyGroup>
<NewLine>%0d%0a</NewLine>
<Space2>%20%20</Space2>
<Space4>$(Space2)$(Space2)</Space4>
<Space6>$(Space4)$(Space2)</Space6>
<HasDependencies>false</HasDependencies>
<HasDependencies Condition="#(MyPackage) != ''">true</HasDependencies>
<Nuspec>$(Nuspec)<?xml version="1.0" encoding="utf-8"?>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)<package >$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space2)<metadata>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<id>$id$</id>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<version>$version$</version>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<title>$title$</title>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<authors>$author$</authors>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<owners>$author$</owners>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<requireLicenseAcceptance>false</requireLicenseAcceptance>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<licenseUrl>https://Your Company.com</licenseUrl>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<icon>PackageIcon.png</icon>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<projectUrl>http://Your Company.com</projectUrl>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<description>$description$</description>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<releaseNotes>$description$</releaseNotes>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<copyright>$copyright$</copyright>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<tags>$title$ Your Company Your Company.com</tags>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<dependencies>$(NewLine)</Nuspec>
<Nuspec Condition="$(HasDependencies)">$(Nuspec)$(Space6)<group targetFramework=".NETFramework4.8">$(NewLine)</Nuspec>
<Nuspec Condition="$(HasDependencies)">$(Nuspec)#(NuspecContent -> '$(Space6)<dependency id="%(PackageID)" version="%(Version)"/>', '$(NewLine)')$(NewLine)</Nuspec>
<Nuspec Condition="$(HasDependencies)">$(Nuspec)$(Space6)</group>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)</dependencies>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space2)</metadata>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space2)<files>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space4)<file src="..\**\PackageIcon.png"/>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)$(Space2)</files>$(NewLine)</Nuspec>
<Nuspec>$(Nuspec)</package>$(NewLine)</Nuspec>
</PropertyGroup>
<WriteLinesToFile Lines="$(Nuspec)" File="$(MSBuildProjectDirectory)\$(MSBuildProjectName).nuspec" Overwrite="true"/>
</Target>
The generated .nuspec file will be:
<?xml version="1.0" encoding="utf-8"?>
<package >
<metadata>
<id>$id$</id>
<version>$version$</version>
<title>$title$</title>
<authors>$author$</authors>
<owners>$author$</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<licenseUrl>https://company.com</licenseUrl>
<icon>PackageIcon.png</icon>
<projectUrl>http://company.com</projectUrl>
<description>$description$</description>
<releaseNotes>$description$</releaseNotes>
<copyright>$copyright$</copyright>
<tags>$title$ company company.com</tags>
<dependencies>
<dependency id="Company.Globals" version="2022.7.19"/>
<dependency id="Portable.BouncyCastle" version="1.9.0"/>
</dependencies>
</metadata>
<files>
<file src="..\**\PackageIcon.png"/>
</files>
</package>
Its really to hard to achieve anything with MSBuild. Maybe you can create a console app for that and just call console app directly with <Exec Command =""/>. But current approach is friendly with MSBuild. Its not 100% organic approach. MSBuild should provide us a target to get a referenced nuget packages with its referenced version.
I'm trying to extract content files from a Nuget package to a project referencing my package.
Based on Justin Emgarten's comment
Packages.config projects use the content folder
Project.json/PackageReference/NETCore SDK projects use the contentFiles folder
So ok great, I created a .NET Core 2.1 Console Application project and followed the NuGet ContentFiles Demystified blog post which was written in 2016 at the time of project.json but should still work nowadays.
I created an image at c:\dev\ContentFilesExample\contentFiles\any\any\images\dnf.png then created a c:\dev\ContentFilesExample\ContentFilesExample.nuspec file and copy pasted the content:
<?xml version="1.0"?>
<package>
<metadata minClientVersion="3.3.0">
<id>ContentFilesExample</id>
<version>1.0.0</version>
<authors>nuget</authors> <!-- The NuGet team authored this package -->
<owners>nuget</owners> <!-- The NuGet team owns this package -->
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>A content v2 example package.</description>
<tags>contentv2 contentFiles</tags>
<!-- Build actions for items in the contentFiles folder -->
<contentFiles>
<!-- Include Assets as Content -->
<files include="**/images/*.*" buildAction="EmbeddedResource" />
</contentFiles>
</metadata>
</package>
Then I generated the Nuget package with the command nuget pack ContentFilesExample.nuspec and opened it using Nuget Package Explorer
Great my picture is there as expected.
And now the final non-working step. I install this Nuget package in my .NET Core 2.1 project but the image is missing. No trace of the image in the root directory of my project, neither in the obj folder nor in the bin folder.
I tried to close and re-open visual studio as stated in some comments somewhere but that didn't solve the issue.
I also tried to change my .NET Core project style to PackageReference but again, this didn't solve the issue
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ContentFilesExample" Version="1.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
So what am I doing wrong? Are content files in Nuget packages really supported by .NET Core?
Thank you
I ended up on this question after hours and hours of googling for a solution, so I decided to write another answer to make things clear because MS docs suck
<files> element in .nuspec file is for the packer. It tells nuget which files to pack (if there are no <files> element in your nuspec - nuget will use the directory naming convention)
<contentFiles> element is for the consumer - it tells how and when to extract the files.
If you want a file to appear in your project after installing - you have to pack it with a target that says contentFiles/any/any where "any/any" part tells nuget it's for ANY language and ANY framework.
(optional) if you also want this file to work with the old nuget mode, that uses packages.config - you have to pack it again, 2nd time, this time - to "content" folder, so older consumers can still use it.
nuspec
<metadata>
...
<contentFiles>
<files include="**/myfile.cs" />
</contentFiles>
</metadata>
<files>
<file src="myfile.cs" target="contentFiles\any\any" /> <!-- this is for new format -->
<file src="myfile.cs" target="content" /> <!-- this is for the old format -->
</files>
PS. Some more details in my blog post here
nupkg should have contentFiles/ directory:
Install to netcore project:
It won't be a loose file in the consuming project, it will be an EmbeddedResource when you build the project:
For me, contentFiles not working for ProjectReferenes. I need to use my own c++ dll with c# proxy. For universal nuget for packages.config and PackageReferences I've done next:
c++ dll and MyCompany.MyDep.CppClient.targets was added to nuget packet project:
CppClient (solution dir)
CppClient (c# proxy project dir)
lib\mycpp.dll (c++ dll)
MyCompany.MyDep.CppClient.targets
CppClient .csproj
...
CppClient .sln.
To CppClient.csproj was added next declaration:
-- This is for packages.config projects
Always
true
content\$(TargetFramework)
-- This is for ProjectReferenes projects - dll
Always
true
build\$(TargetFramework)
-- This is for ProjectReferenes projects too - targets for copy dll
Always
true
build\$(TargetFramework)
MyCompany.MyDep.CppClient.targets is:
%(RecursiveDir)%(FileName)%(Extension)
PreserveNewest
From CppClient (solution dir) run command
dotnet pack CppClient -c Release --output ./package /p:Version=1.0.0 /p:PackageID=MyCompany.MyDep.CppClient
MyCompany.MyDep.CppClient.1.0.0.nupkg has next structure:
MyCompany.MyDep.CppClient.1.0.0
build\arch
MyCompany.MyDep.CppClient.targets
mycpp.dll
content\arch
mycppdll
lib\arch
CppClient.dll
...
MyCompany.MyDep.CppClient.1.0.0.nupkg can be installed to projects with both types of nuget packages management.
For projects with packages.config works magic part of content directory in nuget pack, all it contents will be copied to target project folder, AFTER NUGET PACK IS INSTALLED TO PROJECT. Then it should be copied to final bin directory for being downloaded in runtime (you shuold do it by youself).
For projects with ProjectReferenes works magic copy build\arch\mycpp.dll by build\arch\MyCompany.MyDep.CppClient.targets not right after you installed nuget pack, but WHEN TARGET PROJECT IS ALREADY BUILT. mycpp.dll not be copied to target project sources dir after nuget pack is installed. It will be include in referenced nuget of target project and be copied direct to output dir for binary after target project is built.
I've run into a problem when upgrading a .NET 4.6 project to .NET Core 2.0. All our projects use a custom StyleCop ruleset which is provided by a NuGet package. The ruleset is in a file called custom.ruleset and lives in the content folder inside the package. All our projects consume this package and so get a copy of custom.ruleset.
However, in Core 2.0 and Standard 2.0 projects this doesn't work. Files are no longer copied from the content folder of a package, and we're told to use the contentFiles folder instead.
I have a nuspec that now looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<version>1.0.11</version>
<metadata>
...
<contentFiles>
<files include="content\*.ruleset" buildAction="None" copyToOutput="false" flatten="true"/>
</contentFiles>
</metadata>
<files>
<file src="content\**" target="contentFiles/any/any" />
</files>
</package>
With this structure the ruleset appears in Visual Studio under the project, but trying to reference it from the project's .csproj file with <CodeAnalysisRuleSet>custom.ruleset</CodeAnalysisRuleSet> silently fails and reverts to using the default ruleset. I can force it to work by adding <CodeAnalysisRuleSet>$(NuGetPackageRoot)CustomRuleset\1.0.11\contentFiles\any\any\custom.ruleset</CodeAnalysisRuleSet> but this means the csproj will need updating whenever the ruleset changes, so it may as well be a manual process. Any ideas how to fix this?
The idea is to not try to deploy the file as content but add build logic to the NuGet package.
Make sure that the package is structured in the following way:
build\
build\custom.ruleset
build\{YourPackageName}.targets (e.g. CustomRuleset.targets)
This structure causes the .targets file to be automatically imported into the consuming project by convention.
The .targets file should then contain:
<Project>
<PropertyGroup>
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)custom.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>
This will cause the project's ruleset property to be overwritten to the location relative to the .targets file.
Note that this also applies to .net framework projects using the new PackageReference style of NuGet packages (replacement of packages.config) which is opt-in in VS 2017 (15.2+).
Is there any possibility to create a NuGet package containing the source code that can be referenced as library?
When I use the .nuspec for packing the created .nupkg contains the source code but cannot be referenced. I have already tried out to add a library node within the .nuspec as some suggested on SO but the resulting .nuspec does not match the standard and thus cannot be created.
When using .csproj for packing the .nupkg does only contain the .dll. It can be referenced but cannot be debugged because it does not contain any source code.
How could I achieve both? A referanceable library that contains source code.
In advance thank you for your time.
Here's a .nuspec file I use to package sources from multiple directories that get used as a library in other projects:
<?xml version="1.0"?>
<package >
<metadata>
<id>Your.Package</id>
<version>1.0.14</version>
<authors>me</authors>
<owners>me</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Class library.</description>
<releaseNotes>Initial release.</releaseNotes>
<copyright>Copyright 2017</copyright>
<tags>some tags</tags>
</metadata>
<files>
<file src="*.cs" target="content/App_Packages/<YourPackage>.Sources" />
<file src="Configuration/*.cs" target="content/App_Packages/<YourPackage>.Sources" />
</files>
</package>
Just change the "file" tags to reference the files you're trying to include.
When you're ready to create the .nupkg file, cd to the directory containing your .nuspec file and run:
nuget pack .nuspec
There's now the csproj tag EmbedAllSources. What that does is embed your source code into your NuGet package.
Usage is like this:
<EmbedAllSources>True</EmbedAllSources>
Embedding the source code will allow people to, for example, navigate to your method definitions and see the code just the way you've written it, as opposed to, not being able to navigate to definitions, at all, or rely on decompiled code.
Adding the debug symbols to the above will allow your users to put breakpoints in your code and step through it during debugging.
If that is what you want, add this to your csproj:
<DebugType>Embedded</DebugType>
<EmbedAllSources>True</EmbedAllSources>
Summary
When I package a library using NuGet and reference it in another project the referring project will pull additonal files in to the build directory.
Working Case
Project: ReferenceLibrary
Output: ReferenceLibrary.dll
Project: DerivedLibrary
Output: DerivedLibrary.dll
References: ReferenceLibrary (Copy Local = False)
Project: ConsoleApplication
Output: ConsoleApplication.exe
References: DerivedLibrary
Edit: The reference library is not copied because it is resolved at runtime. There's several versions depending on the target. The reference in derive proj. is so I can code against it.
If I build this then only DerivedLibrary.dll is copied to the ConsoleApplication build folder (i.e. bin/Release).
Non-working Case
Project: ConsoleApplication
Output: ConsoleApplication.exe
Package: DerivedLibrary.nupkg (depends on ReferenceLibrary.nupkg)
A project reference is added to DerivedLibray.dll. Both DerivedLibrary.dll and the ReferenceLibrary.dll are copied from their packages.
I can see it being copied in the MSBUILD log.
_CopyFilesMarkedCopyLocal:
Copying file from "c:\...\ReferenceLibrary.dll" to "bin\Debug\ReferenceLibrary.dll"
Even though it's not referenced in the .csproj anywhere.
I can't tell if this is a NuGet problem (due to how it unpacks things) or a Visual Studio project (how it copies referenced assemblies and encodes the requirements in other assemblies).
A possible solution I've found is to use a post build target to delete the offending references.
In the derived library add a DerivedLibrary.targets file.
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="RemoveUnwantedReferences" AfterTargets="Build">
<Message Text="Removing unwanted references"/>
<Delete Files="$(OutputPath)ReferenceLibrary.dll"/>
</Target>
</Project>
Then in the .nuspec include it
<package>
...
<files>
<file src="Targets/DerivedLibrary.targets" target="/build/DerivedLibrary.targets" />
</files>
</package>
Then when someone installs the package the post build hook will be added. When they build the files that are copied will then be deleted automatically.