Nuget scripting in VS 2017 - nuget

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>

Related

Excluding nuget package with x64 dll from output directory?

I've just added the nuget package Grpc.Core.Api into one of my projects.
The build platform target for this project is marked as x86, however the build process is placing both grpc_csharp_ext.x64.dll and grpc_csharp_ext.x86.dll into my output directory.
At ~10.2MB, this feels unnecessary. Is there any way to prevent the x64 variant from being included (other than manually adding a delete command in the Post-build event).
I can see these two .dll files: grpc_csharp_ext.x64.dll and grpc_csharp_ext.x86.dll after installing Grpc.Core NuGet package, and if I only installing Grpc.Core.Api NuGet package, they won’t be generated.
By checking the detailed MSBuild output log, this two files are copied by default task Copy. The logic(or control) of judging whether to copy or skip copying should be stored in .targets file of Grpc.Core NuGet package folder.
I then find the Grpc.Core.targets file under …\MyProject\packages\Grpc.Core.xxxxx\build\net45. If you find and open it, you will see the related settings:
<ItemGroup Condition="'$(Grpc_SkipNativeLibsCopy)' != 'true'">
<Content Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-x86\native\grpc_csharp_ext.x86.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>grpc_csharp_ext.x86.dll</Link>
<Visible>false</Visible>
<NuGetPackageId>Grpc.Core</NuGetPackageId>
</Content>
<Content Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-x64\native\grpc_csharp_ext.x64.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>grpc_csharp_ext.x64.dll</Link>
<Visible>false</Visible>
<NuGetPackageId>Grpc.Core</NuGetPackageId>
</Content>
...
The <condition="'$(Grpc_SkipNativeLibsCopy)'!='ture'"> and <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> make grpc_csharp_ext.x64.dll be copied to the project output directory.
I don't think this can be overridden or be changed or be prevented by using MSBuild in .csproj files. As you mentioned, manually adding a delete command in the Post-build event should work, but it works after the file has been copied.
What I think/suggest
I may provide a silly or risky workaround. I don't recommend modifying the Grpc.Core.targets file, but if you change to <CopyToOutputDirectory>Never</CopyToOutputDirectory> for grpc_csharp_ext.x64.dll, this file will not be generated again if you only build for x86.
This maybe needs to be changed by author of this NuGet package, unless these actions(copy ..x64 files to output directory when building under x86) are necessary or for some reasons that we don't notice.
Again, I would agree on considering using Post-build event is better.

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).

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>

nuget package with legacy DLLs

I want to create a nuget package that contains besides .NET assemblies "legacy" DLLs (non .NET DLLs), which are referenced or accessed by the assembly DLLs.
Where do I put these DLLs? How does the users program (exe), which uses my package, get access to these DLLs?
I can only think of two ways the users program can access these DLLs: either there is a PATH environment variable set to the appropriate directory or these DLLs are copied into the bin/Release and bin/Debug directories of the users project.
How would I deal with x86 and x64 versions of the legacy DLLs?
I would look at adding a custom MSBuild .targets to your NuGet package. Inside this .targets file you can define any MSBuild tasks you need which will allow you to hook into the build of the project. So you could have the non-.NET dlls copied into the output directory using MSBuild.
The PostSharp NuGet package is one example that copies extra files around during the build. However its MSBuild .targets file is fairly complex. You would not need to do anything as complicated as that. Probably something simple similar to:
<PropertyGroup>
<PrepareForRunDependsOn>$(PrepareForRunDependsOn);MyPostBuildTarget</PrepareForRunDependsOn>
</PropertyGroup>
<ItemGroup>
<ExtraFile Include="dlls\*.dll" />
</ItemGroup>
<Target Name="MyPostBuildTarget">
<Copy SourceFiles="#(ExtraFile)" DestinationFolder="$(OutputPath)" />
</Target>
The above is only an idea of what you could do.

Automate NuGet package to include only .js files (not within a csproj or nuspec file)

I'm trying to automate creating a NuGet package to include .js files within my web project via Visual Studio 2013 when builds are run. I have done this using the NuGet Package Explorer but this needs to be automated.
I have used the Nuget package "CreateNewNuGetPackageFromProjectAfterEachBuild" and this seems close but the CreateNuGetPackage.ps1 script restricts to csproj files. Has anyone done this? I have searched and read that a powershell solution may be needed.
Does anyone know if this has been solved yet? At this point I'm ready to learn how to write a powershell script.
I suggest you to create proper nuspec file with wildchars like below:
<files>
<file src="bin\Debug\*.dll" target="lib" />
<file src="bin\Debug\*.pdb" target="lib" />
<file src="tools\**\*.*" exclude="**\*.log" />
</files>
and run just: nuget.exe pack yournuspec.nuspec