Nuget packages bundled in teamcity not installing documentation files - nuget

So basically I am building nuget packages in TeamCity via a .proj file that runs a "pack" target:
<MSBuild
Projects="$(MSBuildProjectDirectory)\PROJNAME.csproj"
Targets="Rebuild;pack"
Properties="Configuration=$(Configuration);Version=$(BUILD_NUMBER)" />
With an artifact output of:
PROJNAME\bin\Release\PROJNAME.%build.number%.nupkg
This works nicely for basic consuming of the nuget package, however I am having trouble getting the documentation xml files to work.
I have looked inside the output nupkg and I see that the documentation xml is actually bundled and included in the package, however the problem is that when I finally restore nuget packages in my consuming project, the dll gets copied across as expected, however the documentation does not.
I wondered if this is because of the TC generated .nuspec file, and if I may need to abandon teamcities nuspec and create my own, however I was hoping to avoid this, given it works nicely the way it is, and handles versioning etc.
Is there a simple way to include documentation xml when the package is restored?

In the end i found it came down to 3 things, being:
Ensure projects configuration is set to generate documentation.
Either by adding code manually such as:
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"><DocumentationFile>bin\$(Configuration)\netstandard2.0\Project.documentation.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <DocumentationFile>bin\$(Configuration)\netstandard2.0\Project.documentation.xml</DocumentationFile>
</PropertyGroup>
Or alternatively via the Visual Studio Project properties menu, if you are doing it through VS also make sure you do it for all configurations (as depicted as A in the picture below):
Add EnableDocumentationFile to your .csproj file, eg:
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>project</RootNamespace>
<Configurations>Debug;Release</Configurations>
<EnableDocumentationFile>true</EnableDocumentationFile>
</PropertyGroup>
and most importantly let your project know (again in your .csproj) that it should be copying over the documentation file, and use PackageFlatten if you want it to appear at the same level as your package dll:
<ItemGroup>
<None Remove="bin\$(Configuration)\netstandard2.0\Project.documentation.xml" />
</ItemGroup>
<ItemGroup>
<Content Include="bin\$(Configuration)\netstandard2.0\Project.documentation.xml">
<Pack>true</Pack>
<PackageCopyToOutput>true</PackageCopyToOutput>
<PackageFlatten>true</PackageFlatten>
</Content>
</ItemGroup>

Related

Output Directory of native dll bundled with NuGet

I am trying to build a NuGet package that includes native DLLs which are to be placed in the output folder when a project uses the package. I have tried to use the several suggestions from this question, but I am always running in the same problem.
My current NuGet package layout is like this:
\build
packageId.targets
file1.dll
file2.dll
\lib
\netstandard1.4
assembly.dll
The contents of packageId.targets is:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<NativeLibs Include="$(MSBuildThisFileDirectory)\*.dll"/>
<None Include="#(NativeLibs)" Link="$(RecursiveDir)$(Filename)$(Extension)">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
This should, according to the answers of the other questions, lead to my DLLs being placed in the bin\Debug directory of the project using the package. However, they are not. Instead, they are placed in bin\Debug\packages\packageId\build.
Now I have experimented a lot, and I noticed more and more strange behavior which I cannot make any sense of:
If I move the DLLs to the root of the NuGet package (like one answer suggests) and change the .targets file accordingly, they are not copied at all. There also is no error message.
If I change the .targets file to only reference file1.dll in both Include= and Link=, both files get copied anyway.
So I wondered if some policy just ignores the .targets file and copies whatever is in build to that path in the output folder, but when I remove the .targets file, the DLL files will not get copied anymore.
Now I understand even less what's happening.
What do I need to change to get the DLLs copied right into bin\Debug?
The new way to handle runtime-specific assents in NuGet is to use the runtimes folder to place native assets:
\lib
\netstandard2.0
ManagedWrapper.dll
\runtimes
\win-x86
\native
NativeThing.dll
\win-x64
\native
NativeThing.dll
\linux-x64
\native
libNativeThing.so
\osx-x64
\native
libNativeThing.dylib
If the package is consumed from a .NET Framework project, you may need to add a reference to the Microsoft.NETCore.Platforms package wich provides the runtime graph (runtimes.json) for NuGet to provide proper RID mappings if you don't use base RIDs (e.g. win10-x64 falls back to win-x64 resources).

Nuget scripting in VS 2017

I want to add a custom install script for my VS 2017 NuGet package.
Problem is, support for the install.ps1/uninstall.ps1 mechanism was removed. init.ps1 still works, but it would run every time the solution is opened, and that is unacceptable (it's a potentially lengthy process).
I read it's possible to define custom msbuild targets in the build dir, but I cannot get that to work because it requires manipulating the .nuspec file to include the files, and I can't see how to do that in VS 2017 with just the .csproj file.
but I cannot get that to work because it requires manipulating the .nuspec file to include the files
You can use the NuGet Package Explorer to add custom msbuild .targets in the build directory without manipulating the .nuspec file:
I can't see how to do that in VS 2017 with just the .csproj file.
As you know, Powershell script support was modified to no longer execute install and uninstall scripts, so we could not custom install scripts that is called when installing the nuget package, otherwise, we need to overwrite the NuGet API in visual Studio: IVsPackageInstaller interface(Not recommended).
So as a workaround, we could use define custom msbuild .targets file to achieve what you want achieve by the custom install script after install the nuget package. For example, you want custom install nuget script to change the default dll output, you can use a .target file with copy task to achieve it, you can create a file build\MyNuGet.targets containing:
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<MySourceFiles Include="$(ProjectDir)MyFolder\**" />
</ItemGroup>
<Target Name="MyNuGetCustomTarget" AfterTargets="Build">
<Copy SourceFiles="#(MySourceFiles)" DestinationFolder="$(OutDir)" />
</Target>
</Project>

Is there an alternative to contentFiles with projects that use packages.config?

I have a nuget package with content that I want to be copied to the build output when users install my package. There is support for this: NuGet ContentFiles Demystified in NuGet v3.3. However, it only works in projects that use project.json. The contentFiles are not copied to my build output when I have a project that uses packages.config.
Is there an alternative or workaround I could use in order to make my NuGet package work on projects that use either a project.json or packages.config?
A quick search on StackOverflow reveals the following question which I think covers what you are asking for:
Set content files to "copy local : always" in a nuget package
You can put your files inside a Content directory inside the NuGet package.
In your .nuspec file:
<file src="css\mobile\*.css" target="content\css\mobile" />
When you install that into your project it will add the css\mobile directory to your project and the files inside that directory.
However that only adds the files to the project. In order to get them to be copied to your output directory you would either need to use a PowerShell script to modify the project item's copy local information.
An alternative, possibly a better way, would be to use a custom MSBuild .targets file. This will be added as an import to your project and then inside your .targets file you can add the files you want and specify the copy to output information directly as though it was part of your project. NuGet .nupkg file content:
\build
\Net45
\MyPackage.targets
\Foo.txt
MyPackage is the id of the NuGet package above.
Inside the .targets file you specify the files (e.g. Foo.txt).
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="Foo.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

How do you upgrade the *.props included in a NuGet package?

I'm working on an internal NuGet package that adds a pre-build event.
It does this by specifying a build folder containing a MyPackage.props file per the documentation.
Here is the contents of the props file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PreBuildEvent>Some commands go here</PreBuildEvent>
</PropertyGroup>
</Project>
If the project has never had a pre-build event, the event is created. However, if there is an existing PerBuildEvent element in the csproj file, the new value does not get populated. I can get it to work if I open up the csproj file and manually delete the appropriate PropertyGroupElement:
<PropertyGroup>
<PreBuildEvent>Some command line stuff</PreBuildEvent>
</PropertyGroup>
However, I have to delete if from there, as just deleting the contents of the pre-build event in the UI does not allow the new value to be written.
I want to use the convention based method over doing this in install.ps1 because the documentation specifies:
[NuGet 3.x] This script will not be executed in projects managed by project.json
...and (I left this part out before) is there a way to do this when there is no csproj file?
What's going on?
I would suggest you do not use a prebuild event in your .props since I would expect that you do not want to overwrite an existing one in the project.
Instead you could look at using another target so that your logic runs before the build by using the BeforeTargets:
<Target Name="MyBeforeBuild" BeforeTargets="Build">
<Message Text="### MyBeforeBuild ###" Importance="high" />
</Target>
You may also want to look at using the DependsOnTargets attribute if you need your pre-build event to run after some other target.
<Target Name="MyTarget" DependsOnTargets="$(CoreCompileDependsOn)">
</Target>

How do I deploy XULRunner folder to output directory after installing abcpdf gecko via nuget?

I installed the ABCpdf.ABCGecko package via nuget, and it gave me this dialog:
Finished! Please deploy the XULRunner folder to your output directory manually.
I don't really know wtf this means... I have an idea, but don't know precisely where or how to modify my build configuration to allow this to occur. Has anyone done this, and if so, how?
My original attempted answer worked fine for my development setup, but didn't work on our staged deployment setup, as for some reason it didn't include the XULRunner files inside the web package created using MSDeploy. I've found what seems to be a simpler setup, below:
<ItemGroup>
<Content Include="XULRunner\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
I'm not 100% sure if this works universally, but it seems to work better in every development and deployment scheme I've encountered thus far.
I found how to accomplish this via this SO answer. The relevant changes to the project's .csproj file are below:
<Target Name="AfterBuild">
<CallTarget Targets="CopyXULRunnerToDeployFolder" />
</Target>
<Target Name="CopyXULRunnerToDeployFolder">
<ItemGroup>
<MyFiles Include="XULRunner\**\*.*" />
</ItemGroup>
<Microsoft.Build.Tasks.Copy SourceFiles="#(MyFiles)" DestinationFiles="#(MyFiles->'$(OutputPath)\XULRunner\%(RecursiveDir)%(Filename)%(Extension)')"/>
</Target>