Excluding the library being built from nuget package in .NET Standard - nuget

Bear with me - this is an unusual scenario.
I have 4 projects in my solution. The top most project references the 3 other projects. None of the 3 other projects reference each other. So the architecture is like this:
Now, when I build project A I want it to produce a nuget package containing projects B, C and D but not project A. As this is in .NET standard I can configure the packages tab of project A to produce a nuget package automatically when it builds by checking the 'Generate NuGet package on build option.' Then, I can get it to include B, C and D by making the following changes to A's csproj file:
<ItemGroup>
<ProjectReference Include="..\B.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
<ProjectReference Include="..\C.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
<ProjectReference Include="..\D.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
<Version>1.0.0-beta</Version>
<PackageId>A</PackageId>
<Company></Company>
<Product>A</Product>
<Description></Description>
<Authors></Authors>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="#(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'all'))" />
</ItemGroup>
</Target>
Ideally I would like to add a line to remove A.dll from the nuget package. Is this possible? A is a wrapper project which consuming code will never need to use. It is not possible for B, C and D to reference each other.
UPDATE
This is how I solved it (thanks #tom redfern)
I created a nuspec file manually:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>A</id>
<version>1.0.0-beta</version>
<authors>Foo</authors>
<owners>Bar</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>A package</description>
<dependencies>
<group targetFramework=".NETStandard2.0">
</group>
</dependencies>
</metadata>
<files>
<file src="bin\Release\netstandard2.0\B.dll" target="lib\netstandard2.0\B.dll" />
<file src="bin\Release\netstandard2.0\C.dll" target="lib\netstandard2.0\C.dll" />
<file src="bin\Release\netstandard2.0\D.dll" target="lib\netstandard2.0\D.dll" />
</files>
</package>
Then in my .csproj file for A I put the following to automatically pack it after a build:
<Target Name="__PackNuGetPackage" AfterTargets="Build">
<Exec Command="$(NugetPackage)nuget.exe pack "A.nuspec"" />
</Target>

Using patented(1) elite(2) debugging skills, we can figure out if it's possible without manually creating and maintaining a nuspec file.
First, let's start with NuGet's docs on creating a package with the dotnet CLI. It says "msbuild -t:pack is functionality equivalent to dotnet pack". So, first hint, it's just running MSBuild targets.
So, run dotnet msbuild my.csproj -pp:pp.txt. This "pre-processes" (evaluates all MSBuild import statements and writes the result into a single file) the csproj (just a standard MSBuild file). We then search for the pack target, and scroll up until we find the filename of the file that was imported. We see it's NuGet.Build.Tasks.Pack.targets, and since NuGet is open source on GitHub, I can point you to the source.
Searching NuGet.Build.Tasks.Pack.targets for Condition, to see what extensibility options the NuGet team has provided, I see <IncludeBuildOutput Condition="'$(IncludeBuildOutput)'==''">true</IncludeBuildOutput>. So, settings <IncludeBuildOutput Condition="'$(IncludeBuildOutput)'==''">false</IncludeBuildOutput> in your csproj, might work.
(1) not patented
(2) standard, but since people don't modify MSBuild files anywhere near as often as C#, the skills and tools aren't as well known

You can achieve this by using a nuspec file. Use nuspec when you need absolute control over the nuget pack process. A simple nuspec file:
<package >
<metadata>
<id>MyPackage</id>
<version>1.0</version>
<authors>Something</authors>
<owners>Something</owners>
<description>Somthing</description>
<copyright></copyright>
<dependencies>
<!-- any nuget package dependencies -->
<dependency id="AnotherPackage" version="2019.2.4.1" />
</dependencies>
</metadata>
<files>
<!-- this is where you can have complete control over which assemblies get added to your package. You can add them individually pr using wildcards. -->
<file src="..\obj\**\*.dll" target="lib" />
</files>
</package>
When you have created your .nuspec file, add it into your solution, and then make your "Nuget Pack" build step read the nuspec file rather than the project file.

Related

Is there a way to create a nuget package consisting multiple projects including some which dont have reference to any other project?

I have following dll's among others in a solution:
Base
Core
Basics
R1
R2
Types
I want to put them all in one single nuget package and upload it to Azure DevOps -> Artifacts. Is this possible ?
Is there a way to create a nuget package consisting multiple projects
including some which dont have reference to any other project?
The short answer is Yes, We could use .nuspec to pack up the assemblies:
Download the nuget.exe.
Create a new project.
Open a cmd and switch path to nuget.exe
Use command line: nuget spec "PathOfProject\TestDemo.csproj"
Open the TestDemo.csproj.nuspec file and modify it and add the assemblies as file; below is my .nuspec file:
<?xml version="1.0"?>
<package>
<metadata>
<id>TestDemo</id>
<version>1.0.0</version>
<authors>Tester</authors>
<owners>Tester</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>TestDemo</description>
<releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
<copyright>Copyright 2017</copyright>
<tags>Tag1 Tag2</tags>
</metadata>
<files>
<file src="ThePathOfTheDll\*.Base.dll" target="lib\net461" />
<file src="ThePathOfTheDll\*.Core.dll" target="lib\net461" />
<file src="ThePathOfTheDll\*.Basics.dll" target="lib\net461" />
<file src="ThePathOfTheDll\*.R1.dll" target="lib\net461" />
<file src="ThePathOfTheDll\*.R2.dll" target="lib\net461" />
<file src="ThePathOfTheDll\*.Types.dll" target="lib\net461" />
</files>
</package>
Use pack command: nuget pack TestDemo.csproj.nuspec
Besides, if your project is donet project, you can edit your csproj file, add an ItemGroup to include the dlls as below: This will pack the other dlls along with your current project dll in the nuget package:
<ItemGroup>
<Content Include="<path to other dll>">
<Pack>true</Pack>
<PackagePath>lib\$(TargetFramework)</PackagePath>
</Content>
</ItemGroup>

Custom NuGet package not installing in wix project

I generate a NuGet that is is just a number of redist files that I want to use in one of my projects. If I install it in a C# or C++ projects, it works. But when I try to install it in a wixproj project and I get the following message:
Could not install package 'package-1.0.0'. You are trying to install this package into a project that targets 'Unsupported,Version=v0.0', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.
I generate the package through a TeamCity task (using NuGet 5.6.0). When trying to generate the package with a NuGet CLI 5.8.1, I get the following warning:
*WARNING: NU5128: Some target frameworks declared in the dependencies group of the nuspec and the lib/ref folder do not have exact matches in the other location. Consult the list of actions below:
Add a dependency group for native0.0 to the nuspec*
Looked at https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu5128, one of the solutions was trying a dependencies group targetFramework, (I used "native0.0") with no success. My nuspec is as follows:
<?xml version="1.0"?>
<package>
<metadata>
<id>package</id>
<version>1.0.0</version>
<authors>package</authors>
<owners>owner</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>my package</description>
<copyright>© 2021 company, Inc</copyright>
<tags>native</tags>
</metadata>
<files>
<file src="downloads\Folder\win32.vs2017\file1.lib" target="lib\native\lib\win32.vs2017\" />
<file src="downloads\Folder\win32.vs2017\file1-debug.lib" target="lib\native\lib\win32.vs2017\" />
<file src="downloads\Folder\Include\**" target="lib\native\include\" />
<file src="build\package.props" target="build\native" />
</files>
</package>
And my props file
<Project>
<PropertyGroup>
<MyVersion>1.0.0</MyVersion>
</PropertyGroup>
</Project>
I can install other NuGet packages into wixprojects, so how I configure mine to work? Thanks.
OK I found it, the issue lies at the line
<file src="build\package.props" target="build\native" />
changing target to "build\" allows the NuGet to be loaded to any project type, included WixProj. Note that the NU5128 warning still exists though, but not an issue for me.

How to pack an x86 / x64 specific C++/CLI DLL with Nuget?

I have a C++/CLI DLL that interfaces a third party native DLL. I want to pack this as Nuget.
I followed this official MS guide, this blog post and read through this other question.
So here is what I did:
First, I created the proper nuspec file:
<?xml version="1.0"?>
<package >
<metadata>
<id>CPlusPlusNativeIFace</id>
<version>1.0.4</version>
<title>CPlusPlusNativeIFace</title>
<authors>Jens Rabe</authors>
<owners>Who owns that</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>A DLL that makes a native third-party DLL available to .net</description>
<releaseNotes>foo</releaseNotes>
<copyright>errm...</copyright>
<tags>foo bar</tags>
</metadata>
<files>
<file src="..\Release\**" target="runtimes/win-x86/lib/net461" />
<file src="..\x64\Release\**" target="runtimes/win-x64/lib/net461" />
<file src="DummyAny\**" target="ref\net461" />
</files>
</package>
Then I compiled the DLL for Release x86 and Release X64. Then I created the DummyAny folder, copied the contents of the x86 one in, and used the corflags utility like in Links 2 and 3 to strip the 32 bit flag.
When I now nuget pack and nuget add, and try to reference that package in another project, I always get:
Could not install package 'CPlusPlusNativeIFace 1.0.4'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.6.1', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.
I double checked that the files are right:
I have the x86 stuff in runtimes/win-x86/lib/net461
I have the x64 stuff in runtimes/win-x64/lib/net461
I have a ref/net461 folder with the manipulated dll in
But I still can't load the package.
I also tried putting the CPU specific DLLs into runtimes/win-x86/native and runtimes/win-x64/native to no avail.
What else am I missing? Does that not work for C++/CLI projects built against .net Framework?
Turned out that the official MS documentation was not usable here.
This question was/is listed as "related" here and the accepted answer there made it work for me. I used the example project on Github as a reference.
So here is how I got it to work:
Opened the project properties, went to Configuration Properties / General, selected All Configurations and All Platforms, and as Output Directory, I specified: $(ProjectDir)bin\$(Platform)\$(Configuration)\
Rebuilt the project for x86 and x64 in Release mode
Adapted the Nuspec to be like this:
<?xml version="1.0"?>
<package >
<metadata>
<id>CPlusPlusNativeIFace</id>
<version>1.0.5</version>
<title>Third Party Proxy</title>
<authors>Jens Rabe</authors>
<owners>foo</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>bar</description>
<releaseNotes>Further experimenting with nuget</releaseNotes>
<copyright>baz moo</copyright>
<tags>quux bletch</tags>
</metadata>
<files>
<file src="bin\Win32\Release\**" target="build\x86" />
<file src="bin\x64\Release\**" target="build\x64" />
<file src="bin\Win32\Release\**" target="lib\net461" />
<file src="CPlusPlusNativeIFace.props" target="build\net461" />
</files>
</package>
Added a CPlusPlusNativeIFace.props which contains the following:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Reference Include="CPlusPlusNativeIFace" Condition="'$(Platform)' == 'x86'">
<HintPath>$(MSBuildThisFileDirectory)..\x86\CPlusPlusNativeIFace.dll</HintPath>
</Reference>
<Reference Include="CPlusPlusNativeIFace" Condition="'$(Platform)' == 'x64'">
<HintPath>$(MSBuildThisFileDirectory)..\x64\CPlusPlusNativeIFace.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
Now I can do nuget pack CPlusPlusNativeIFace.nuspec and I get a Nuget package that installs correctly.

Nuget Package won't install in UAP

I'm trying to create a custom nuget package out of one of my projects. When I try to install it into the test project that references it, I receive this error:
Package "package" 1.0.5 is not compatible with uap10.0.15063 (UAP,Version=v10.0.15063). Package "package" 1.0.5 supports: net (.NETFramework,Version=v0.0)
This obviously isn't the case because the test project can run fine referencing the Project itself.
I'm building the nuget package based on my nuspec file:
<?xml version="1.0"?>
<package >
<metadata>
<id>Project</id>
<version>1.0.0</version>
<title>Project</title>
<authors>company</authors>
<owners>company</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>desc</description>
<copyright>cp</copyright>
<dependencies>
<group targetFramework="uap ">
<dependency id="Logging" version="1.0.0" exclude="Build,Analyzers" />
<dependency id="Microsoft.NETCore" version="5.0.0" exclude="Build,Analyzers" />
<dependency id="Microsoft.NETCore.Portable.Compatibility" version="1.0.0" exclude="Build,Analyzers" />
<dependency id="NuGet.Build" version="2.12.0" exclude="Build,Analyzers" />
<dependency id="NuGet.CommandLine" version="4.1.0" exclude="Build,Analyzers" />
</group>
</dependencies>
</metadata>
<files>
<file src="bin\Release\*.dll" target="lib" />
</files>
"Logging" is also a custom nuget package I created from the .csproj file of another project.
I've tried removing the tag, and also tried renaming the targetFramework="uap", none of that works.
What could be wrong and what can I try to get this working?
The target doesn't just rely on the NuSpec file, it would depend on the C# project and the dll itself. Go to:
Project> Rightclick> Properties> TargetFramework>
Set it to .Net or whatever. Also, change your output type to a console application rather than a windows application, if that is doable.
Also, you should create the nuspec file using:
Nuget spec < ProjectPath >
This gives us the advantage to just change the metadata for .csproj files, and copies that into the package metadata automatically.
I'm not a 100% sure if this will fix it, but this should be what needs to be done. Best of luck!

Options for placing and updating PowerShell files in Project folder using NuGet

I am building a NuGet package that only contains a set of PowerShell scripts. The desired behavior is for the scripts to be placed in the project and/or solution folder, removed when the package is uninstalled, and updated when the package is updated. These scripts just need to live in the folder, and be copied to output folder (they are deploy scripts).
I've done this before using content target in a nuspec, but this does not work in netstandard/.NET Core applications (i.e., anything that uses PackageReference). The NuGet documentation mentioned the contentFiles element under the metadata element, but that also does not work with PackageReference. The only thing that I have been able to get working at all is copying the PowerShell scripts in tools/init.ps1. I have something partially working, but it doesn't handle the uninstall or upgrade path. And DTE is never fun.
Is there a way to use content files in netstandard?
If not, does there exist a sample or example of how to properly manage the NuGet lifecycle (copy file, update file, delete file)?
EDIT: This is for a console application, but it also should work in an asp.net application.
EDIT2: This is the nuspec that I have tried to do things via the contentFiles element. When I install the package, I don't see anything in project or solution.
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Test</id>
<version>1.0.0</version>
<contentFiles>
<files include="Build.ps1" buildAction="Content" copyToOutput="true" />
</contentFiles>
</metadata>
<files>
<file src="Build.ps1" target="content" />
</files>
</package>
Thanks,
Erick
As you have noticed, NuGet packages referenced via PackageReference no longer modify the project when installing. This is also the case for .NET Framework projects using this new feature (it was made public for non-core projects in VS 2017 15.2).
The content/someScript.ps1 file is still necessary for compatibility with "classic" packages.config based project, but a new feature for PackageReference projects is contentFiles.
When packing manually using a nuspec file, copying a file on build can be done by adding a contentFiles section:
<package>
<metadata>
...
<contentFiles>
<files include="**/*.ps1" buildAction="Content" copyToOutput="true" />
</contentFiles>
</metadata>
<files>
<file src="Build.ps1" target="content" />
<file src="Build.ps1" target="contentFiles/any/any" />
</files>
</package>
See the documentation on contentFiles for more details my example on GitHub.