Nuget does not import .targets - nuget-package

I want to add my .targets file into project via nuget.
I have next .nuspec file:
<package >
<metadata>
...
</metadata>
<files>
<file src="..\..\Rcs\Rcs\bin\Release\Rcs.targets" target="build\Rcs.targets" />
<file src="..\..\Rcs\Rcs\bin\Release\Rcs.dll" target="lib\Xamarin.iOS10\Rcs.dll" />
<file src="..\..\Rcs\Rcs\bin\Release\*.dll" />
<file src="..\..\Rcs\Rcs\bin\Release\*.config" />
</files>
</package>
And .targets file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<RcsDirectory Condition="$(RcsDirectory) == '' Or $(RcsDirectory) == '*Undefined*'">$(MSBuildThisFileDirectory)..\..\</RcsDirectory>
</PropertyGroup>
<UsingTask
TaskName="Rcs.RcsBuildTask"
AssemblyFile="$(RcsDirectory)Rcs.dll" />
<Target AfterTargets="Build" Name="RcsBuildTask">
<RcsBuildTask
ProjectPath="$(MSBuildProjectFullPath)"
RootNamespace="$(RootNamespace)"
/>
</Target>
</Project>
New doesn't added to project after installing this nuget.
Any help will be appreciated

Are you sure the .targets file is really not imported into your Nuget package?
Along with a .nuspec file you should use the Nuget CLI to pack your files. Don't use the dotnet CLI
Once you created your .nupkg file using the nuget pack command, you can open your package using Nuget Package Explorer or simply WinRar (I believe this should work too with 7-zip).
At this point if you see your .targets file or your Rcs.dll are missing it means you have an issue with your .nuspec file.
Ensure your .nuspec file has the name ProjectName.nuspec
OR
Specify the .nuspec file in your .csproj
<PropertyGroup>
[...]
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<NuspecFile>ProjectName.nuspec</NuspecFile>
[...]
</PropertyGroup>
If your .targets file is in your .nupkg then it means its execution is simply doing not what you expect.
When you install a Nuget package, the files are stored to the Nuget cache. On Windows this is located at %userprofile%\.nuget\packages. Your .targets file and your Rcs.dll should be there too
First of all you can include this in your .targets file
<Target Name="TestMessage" AfterTargets="Build" >
<Message Text="***********************************************************" Importance="high"/>
<Message Text="$(MSBuildThisFileDirectory)" Importance="high"/>
<Message Text="***********************************************************" Importance="high"/>
</Target>
When building your project, you will see the current folder is actually your cache (not your project's directory)
If I understand, what you want is to copy your Rcs.dll into your bin folder. To achieve that you can write a similar task in your .targets file
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)\..\lib\Xamarin.iOS10\Rcs.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
This is a normal behavior that the .targets file is not copied to your project referencing your Nuget package. The .targets file should stay in the Nuget cache, but from there, execute a MsBuild command to copy the Rcs.dll file.
I hope you understand my answer and it solves your problem.

I found that by using NuGet Package Explorer that the targets file had to be named correctly. By default, NPE uses .targtets. It appears that other names may not work.
My Id is "Handy.TargetFrameworkVersionCumulativePreprocessorSymbols", but I had named my target file "HandyTargetFrameworkVersionCumulativePreprocessorSymbols.targets".
Once I used "Handy.TargetFrameworkVersionCumulativePreprocessorSymbols" everywhere it just worked as expected.

Related

Automatically update .nupec file with dependencies

I've created a nuget package that is used by another project.
My package references Microsoft.Identity.Web version 1.23.1. When I pull this package into the project where I want to you use it, I don't get told that my package has this dependency, I understand I can add the following to the .nuspec file to fix this:
<dependencies>
<dependency id="Microsoft.Identity.Web" version="1.23.1" />
</dependencies>
Now I'll get the message about also downloading this package when I install my own package.
I would like this to happen automatically, I don't want to have to go into here and update the version numbers and/or add any new dependencies when I update my package.
I'm sure there is a very basic answer to this but I just can't seem to find the answer.
My .csproj for my package:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Identity.Web" Version="1.23.1" />
</ItemGroup>
<ItemGroup>
<None Update=".nuspec">
<SubType>Component</SubType>
</None>
</ItemGroup>
</Project>
The right way is to not use a nuspec at all - they're a bit legacy, and since you're using PackageReference dotnet can get all the info it needs from your project file.
See https://learn.microsoft.com/en-us/nuget/reference/msbuild-targets#pack-target for how to use your project file to specify any other values you've currently got in your nuspec

How to suppress warnings for missing Mac Server (Warning VSX1000)

We have a number of Xamarin iOS projects that are part of our main solution since we need to ensure that they compile as part of the gated check-in. However most of our developers are not using iOS and hence do not configure a connection to a Mac build agent.
During build locally and on our servers, we see this warning:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Xamarin\iOS\Xamarin.iOS.Windows.After.targets(63,5): Warning VSX1000: No Address and User has been specified in order to establish a connection to a Mac Server, so only the main assembly was compiled for project 'MyProject.iOS'. Connect to a Mac Server and try again to build the full application.
Is there some way of configuring whether this should be a warning, so that we can remove it from the Error List in Visual Studio and the build log from the server? Preferably it should be done in the projects so it could be set once for everyone.
We are using latest Visual Studio 2017 and TFS 2017 Update 2 and build vNext.
A dirty workaround is to override the targets that produce the warning - in my case that's fine as I don't need them.
In our iOS project files I conditionally (if a server address is defined) import a target file, AvoidMacBuildWarning.target, that replaces a number of targets.
Parts of the project file:
...
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets"/>
<Import Project="AvoidMacBuildWarning.target" Condition=" '$(ServerAddress)' == '' " />
<ItemGroup>
...
AvoidMacBuildWarning.target:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="_SayHello">
<Message Text="Warning (demoted to message) VSX1000: No Address and User has been specified in order to establish a connection to a Mac Server, so only the main assembly was compiled for project 'MediumService.iOS'. Connect to a Mac Server and try again to build the full application." />
</Target>
<Target Name="_SayGoodbye">
</Target>
<Target Name="_DetectSdkLocations">
</Target>
<Target Name="_CollectBundleResources">
</Target>
<Target Name="_PackLibraryResources">
</Target>
<Target Name="CopyFilesToMacOutputDirectory">
</Target>
</Project>
We do nothing special to change the warning behavior in VSTS/TFS build comparing with local build through visual studio.
As far as I known, suppressing warnings with MSB prefix is still not possible. Refer to: Supress/Disable/Solve Visual Studio Build Warning
You could give a try with /property:WarningLevel=0through MSBuild argument. Not sure if it will work with this kind of warning above. If not, afraid there is no way to bypass it.
You should use /nowarn:VSX1000 per msbuild documentation
I'd like to add a small variation of Tore Østergaard's answer in case you converted your CSPROJ to an SDK-style project (which iOS projects at this time are usually not, but you can make it work).
In an SDK-style project the "system" targets and props are imported via an SDK attribute at the top of the CSPROJ, like this:
<Project Sdk="MSBuild.Sdk.Extras">
... various project settings ...
</Project>
But if you try to use Tore Østergaard's answer, it won't work, because that answer's target overrides will be themselves overwritten by the SDK's targets (which are always imported last).
The workaround is to manually import the SDK targets and props so that you can control their order:
<Project>
<!--
The SDK is imported manually so that certain targets can be overridden (see bottom of file).
Otherwise we could use Project Sdk="MSBuild.Sdk.Extras"
-->
<Import Project="Sdk.props" Sdk="MSBuild.Sdk.Extras" />
... various project settings ...
<!-- See comment at top of file about manually importing SDK -->
<Import Project="Sdk.targets" Sdk="MSBuild.Sdk.Extras" />
<!--
These targets must be imported last so that they override the SDK-provided targets.
These override the Mac build agent command because they are not needed on CI.
-->
<Import Project="AvoidMacBuildWarning.targets" Condition=" '$(SkipMacBuild)' == 'true' " />
</Project>
Note: I also changed the condition to be a specific condition SkipMacBuild, but you can use whatever condition you want that makes sense for your build.
I also had to add an additional "empty target" to AvoidMacBuildWarning.targets to ensure they were also quieted. My full AvoidMacBuildWarning.targets looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Inspired by https://stackoverflow.com/a/47182083 from Tore Østergaard -->
<Target Name="_SayHello">
<Message Text="INFO: This would have been MSBuild warning VSX1000, but it has been ignored by importing this targets file." />
</Target>
<Target Name="_SayGoodbye">
</Target>
<Target Name="_DetectSdkLocations">
</Target>
<Target Name="_CollectBundleResources">
</Target>
<Target Name="_PackLibraryResources">
</Target>
<Target Name="CopyFilesToMacOutputDirectory">
</Target>
<Target Name="_VerifyBuildSignature">
</Target>
<Target Name="_VerifyXcodeVersion">
</Target>
</Project>

Create a nuspec file that uses all the default behaviour but adding one additional file

I want to have a nuspec file that automatically reads all the info from packages.config and so on, building up all the dependencies, but also includes just one single additional file.
Is there a way to do this?
For example, here is a nuspec file that does almost what I want:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
<id>My.Project</id>
<version>1.0.0.0</version>
<owners>Me</owners>
<authors>Me</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<title>My.Project</title>
<description>My.Project</description>
<frameworkAssemblies />
<copyright>Copyright © 2015</copyright>
<tags></tags>
</metadata>
</package>
If my project references ten nuget packages, the above nuspec file will detect that and add them as dependencies when I pack the package together.
But, the moment I add a files element then all the auto-linking to my other nuget dependencies stops:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
<id>My.Project</id>
<version>1.0.0.0</version>
<owners>Me</owners>
<authors>Me</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<title>My.Project</title>
<description>My.Project</description>
<frameworkAssemblies />
<copyright>Copyright © 2015</copyright>
<tags></tags>
</metadata>
<files>
<file src="myfile.dll" target="lib\net45" />
</files>
</package>
Without the auto-linking I effectively have to maintain two copies of all the dependencies for my project: one in the csproj file and one here.
There must be a way to do this?! I want to just add a single extra file to my package, via a nuspec.
If you only need to include an additional file in a package packed from a project, simply add the file to the project and set its Build Action to Content.
It will be added to the package under Content directory and on installing will be added to the consuming project.
Are you using Octopus Deploy?
If using Octopus Deploy this can be resolved by adding /p:OctoPackEnforceAddingFiles=true, which tells OctoPack to include the normal files on top of what's defined in <files>..</files>
Read this for more information
https://octopus.com/docs/packaging-applications/nuget-packages/using-octopack/octopack-to-include-buildevent-files

MSBuild ignores OutDir and always forces rebuild

Our solution contains ~50 projects. They all import a custom .target file that sets the OutDir variable so that all projects build to a common Binaries folder.
Problem is: MSBuild does not check the OutDir folder for the .dlls but keeps looking inside the OutputPath folder (e.g. bin\Debug). As the OutputPath folder is empty it states that each project is not up-to-date and forces a rebuild. This is not an issue on our TFS build agents but it drastically increases the time between hitting F5 and the application starting on our development machines. Debugging becomes quite a pain.
From the Binaries folder we copy the .dlls to our applications folder structure which we use for generating setups etc. Thus simply dropping the use of OutDir in favor of various OutputPaths is not an option.
Is there any way to tell MSBuild to also check the OutDir folder when looking for existing .dlls?
Following import in csproj files works for me in VS 2015. I added comments about which settings make it fail:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<!-- to distinguish by $(Platform) does not work, a rebuild is triggered since the up-to-date check fails -->
<!-- if IntermediateOutputPath is not set here at all, it does not work either, i.e. it always rebuilds -->
<IntermediateOutputPath>$(SolutionDir)obj\$(Configuration)\$(MSBuildProjectName)\</IntermediateOutputPath>
<UseCommonOutputDirectory>False</UseCommonOutputDirectory>
<DisableFastUpToDateCheck>false</DisableFastUpToDateCheck>
</PropertyGroup>
<PropertyGroup Condition=" '$(OutputType)' == 'Library' ">
<!-- To distinguish by \lib\ does not work, a rebuild is triggered since the up-to-date check fails -->
<!-- <OutputPath>$(SolutionDir)bin\$(Configuration)\$(Platform)\lib\</OutputPath> -->
<OutputPath>$(SolutionDir)bin\$(Configuration)\$(Platform)</OutputPath>
<OutDir>$(OutputPath)</OutDir>
</PropertyGroup>
<PropertyGroup Condition=" '$(OutputType)' == 'Exe' ">
<OutputPath>$(SolutionDir)bin\$(Configuration)\$(Platform)\</OutputPath>
<OutDir>$(OutputPath)</OutDir>
</PropertyGroup>
</Project>
The file is included in csproj files just before Import Microsoft.CSharp.targets:
.csproj file:
<!-- position of include is important, OutputType of project must be defined already -->
<Import Project="$(SolutionDir)ComponentBuild.props" Condition="Exists('$(SolutionDir)ComponentBuild.props')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
Also see my own SO question about it:
MSBuild, OutputPath to a lib directory is not honoured

Can NuGet add a .cs file to the destination project?

I want to create a NuGet package that adds a .cs file (a base class the package consumer is encouraged to later modify) to the root of the destination project during installation.
Is that possible? Everything I've found so far says "no, you can only install files below the package's directory".
Just put your .cs file in a folder called "content", at the root of the package.
from the docs:
"you can layout a directory structure that follows the NuGet conventions.
tools - The tools folder of a package is for PowerShell scripts and programs accessible from the Package Manager Console. After the folder is copied to the target project, it is added to the `$env:Path (PATH) environment variable.
lib - Assemblies (.dll files) in the lib folder are added as assembly references when the package is installed.
content - Files in the content folder are copied to the root of your application when the package is installed.
Think of the Content folder as the root of your target application. For example, if I want a package to add an image in the /images directory of the target application, make sure to place the image in the Content/images folder of the package."
see: http://docs.nuget.org/docs/creating-packages/creating-and-publishing-a-package#From_a_convention_based_working_directory
You can also use the <files> section of the nuspec to move your file into the content folder when the package is being built:
<?xml version="1.0"?>
<package>
<metadata>
...
</metadata>
<files>
<file src="App.Template.config" target="content" />
<file src="Program.template.cs" target="content" />
</files>
</package>
If you are creating a PackageReference project like netstandard2.0 library, the following should work:
.nuspec file:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata minClientVersion="3.3.0">
...
<contentFiles>
<files include="**/Pages/Shared/*.*" buildAction="Content" />
</contentFiles>
</metadata>
<files>
<file src="bin\Release\netstandard2.0\*.dll" target="lib\netstandard2.0" />
<file src="contentFiles\**\*" target="contentFiles" />
</files>
</package>
This will copy the contentFiles folder to the project. You can specify different files by programming language and platform. If you would like to add to all of them
place files under contentFiles/any/any.

Resources