Azure Function PostBuild File Copy being lost - entity-framework-core

I'm doing an MSBuild in Visual Studio of a C# Azure Function. Most of the content is placed in $(TargetDir)/bin. I need to copy the Api.dll from there to $(TargetDir) for Entity Framework Migration. eg:
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="echo copy /Y "$(TargetDir)bin\Api.dll" "$(TargetDir)"" />
</Target>
The copy appears to work, but is not there when the build is completed.
If I do the copy as a batch file with a directory listing before and after the file IS copied.
But its not there when I try to do add-migration
So I guess the project build is recreating the Target folder after PostBuildEvent ???
The Api project builds OK but when I run add-migration fist I get:
An assembly specified in the application dependencies manifest (Api.deps.json) was not found:
package: 'Api', version: '1.0.0'
path: 'Api.dll'
The dll is not in $(TargetDir) but one folder lower in $(TargetDir)bin

this is due to RemoveRuntimeDependencies task removes this assemblies. Add <_FunctionsSkipCleanOutput>true<_FunctionsSkipCleanOutput> to .csprojwithinPropertyGroup.

Related

NuGet package: Copy DLLs to subdirectories in buildoutput

I want to create a NuGet package that copies the DLLs into a subdirectory of the output directory.
This is what the folder structure of my package looks like:
Package root
lib
net48
x64
First.dll
Second.dll
x86
First.dll
Second.dll
The DLLs should be copied to the respective subdirectory in the output folder as follows:
Output directory
x64
First.dll
Second.dll
x86
First.dll
Second.dll
I have tried the files attribute in the nuspec file:
<files>
<file src="lib\net48\amd64\*.dll" target="amd64\" />
<file src="lib\net48\x86\*.dll" target="x86\" />
</files>
When building the package the following warning appears for each DLL I use:
WARNING: NU5100: The assembly 'amd64\First.dll' is not inside
the 'lib' folder and hence it won't be added as a reference when the
package is installed into a project. Move it into the 'lib' folder if
it needs to be referenced.
Neither the subfolders are created nor the DLLs are copied into the output folder after I restored all packages.
How can I configure the nuspec file so that the DLLs are copied into the subfolders? Do I need an install.ps1 script?
I'm using .NET Core (and .NET 5) projects. And packaging one component with multiple project DLLs. Can do this by modifying prject files.
So if you also have .NET Core projects add the following section to your .csproj file (to the project which should be packaged) to package DLL, change the DLL names and path as you need it.
<ItemGroup>
<_PackageFiles Include="$(OutputPath)\First.dll">
<BuildAction>None</BuildAction>
<PackagePath>x64</PackagePath>
</_PackageFiles>
<_PackageFiles Include="$(OutputPath)\First.dll">
<BuildAction>None</BuildAction>
<PackagePath>x86</PackagePath>
</_PackageFiles>
</ItemGroup>

Building nuget file from nuspec with Azure Pipelines

I have ran into a strange problem and have been trying to fix for a couple of days. Locally, I can build my project just fine with the following nuspec file. The nuspec file is saved in the repo and copied local when built from the c# project and it is under a sub folder called "nugetcreation". Locally, I can run the nuspec file as is and it generates the nuget package.
Folder setup:
project
-project files
-nugetcreation
-readme and nuspec files
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>my.Utility.TraceWriter</id>
<version>1.0.0-beta</version>
<title>my.Utility.TraceWriter</title>
<authors>justme</authors>
<owners>justme</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>custom trace items</description>
<releaseNotes>initial release</releaseNotes>
</metadata>
<files>
<file src="Content\MyReadMes\My.Utility.TraceWriter.md" target="content\net461\MyReadMes\My.Utility.TraceWriter.md" />
<file src="..\My.Utility.TraceWriter.dll" target="lib\net461\My.Utility.TraceWriter.dll" />
<file src="..\My.Utility.TraceWriter.pdb" target="lib\net461\My.Utility.TraceWriter.pdb" />
</files>
</package>
The problem:
When I am building an Azure Pipeline, I tell it to run the nuspec file and I am getting an error
##[error]The nuget command failed with exit code(1) and error(Error NU5019: File not found: '..\My.Utility.TraceWriter.dll'.
But it is absolutely being generated correctly from the vsbuild process
CopyFilesToOutputDirectory:
Copying file from "d:\a\1\s\My.Utility.TraceWriter\My.Utility.MethodTracer\obj\Release\My.Utility.TraceWriter.dll" to "d:\a\1\s\My.Utility.TraceWriter\My.Utility.MethodTracer\bin\Release\My.Utility.TraceWriter.dll"
The nuget creation step in the azure pipeline is pretty basic, nothing fancy. All of the fancy stuff I am keeping in the nuspec file. I am trying to get this to work on a basic project with the nuspec file because I have much more complicated nuget packaging coming later so this is my test version.
- task: NuGetCommand#2
displayName: 'Creating nuget package'
inputs:
command: 'pack'
packagesToPack: '**/*.nuspec'
versioningScheme: 'off'
arguments: '--configuration $(buildConfiguration)'
So far I have tried using:
**\My.Utility.TraceWriter.dll (no error, but no dlls are in the lib folder. acts as if that line is just skipped)
bin**\My.Utility.TraceWriter.dll
.\My.Utility.TraceWriter.dll
$configuration$\My.Utility.TraceWriter.dll
**\$configuration$\My.Utility.TraceWriter.dll
...nothing works. Does anyone have any ideas about why the azure pipeline doesn't accept the correct (..\My.Utility.TraceWriter.dll) relative path entry on the nuspec file and how to fix it?
My forehead hurts from banging my keyboard against it...
--EDIT--
A little more info. It appears that 2 things are happening when the nuget pack command is ran. The entire output is below but it looks like after the nuget successfully builds it is trying to pack it again and this time can't find the files??
Added file '_rels/.rels'.
Added file 'My.Utility.TraceWriter.nuspec'.
Added file 'content/net461/MyReadMes/My.Utility.TraceWriter.md'.
Added file 'lib/net461/My.Utility.TraceWriter.dll'.
Added file 'lib/net461/My.Utility.TraceWriter.pdb'.
Added file 'package/services/metadata/core-properties/f2a4d059fea6458dac5889de57641f5b.psmdcp'.
Successfully created package 'D:\a\1\a\My.Utility.TraceWriter.1.0.0-beta.nupkg'.
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 .NETFramework4.6.1 to the nuspec
Attempting to pack file: D:\a\1\s\My.Utility.TraceWriter\My.Utility.MethodTracer\nuget information\My.Utility.TraceWriter.nuspec
C:\hostedtoolcache\windows\NuGet\5.4.0\x64\nuget.exe pack "D:\a\1\s\My.Utility.TraceWriter\My.Utility.MethodTracer\nuget information\My.Utility.TraceWriter.nuspec" -NonInteractive -OutputDirectory D:\a\1\a -Properties Configuration=Release -Verbosity Detailed
Error NU5019: File not found: '..\My.Utility.TraceWriter.dll'.
NuGet Version: 5.4.0.6315
NuGet.Packaging.Core.PackagingException: File not found: '..\My.Utility.TraceWriter.dll'.
Stupid. the packagesToPack: '**/*.nuspec' is pulling both nuspecs: the one in source AND the one copied to the output bin folder.
redefining fixed the issue

Azure Devops: Building a multi-project solution in release mode, but looks in debug for missing assembly

I'm trying to build a multi-project solution in Azure DevOps for deployment to Azure. This solution builds fine on my local machine, but I get the following build error in Azure.
##[error]TCGTools.net\Controllers\SettingsController.cs(8,7): Error CS0246: The type or namespace name 'TCGSniperCore' could not be found (are you missing a using directive or an assembly reference?)
TCGSniperCore is a .netcore library in my solution. The MVC project references this library.
After skimming the full log file, I found that the solution is building the .netcore library in release mode, but then looks for the .dll in the debug folder.
Console output when building the library:
CopyFilesToOutputDirectory:
Copying file from "obj\Release\netcoreapp2.2\TCGSniperCore.dll" to
"bin\Release\netcoreapp2.2\TCGSniperCore.dll".
TCGSniperCore ->
D:\a\1\s\tcgsnipercore\bin\Release\netcoreapp2.2\TCGSniperCore.dll
Copying file from "obj\Release\netcoreapp2.2\TCGSniperCore.pdb" to
"bin\Release\netco
Console output when building the MVC project:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(2110,5): warning MSB3245: Could not resolve this reference. Could not locate the assembly "TCGSniperCore". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. [D:\a\1\s\TCGTools.net\TCGTools.net.csproj]
For SearchPath "{HintPathFromItem}".
Considered "..\tcgsnipercore\bin\Debug\netcoreapp2.2\TCGSniperCore.dll", but it didn't exist.
For SearchPath "{RawFileName}".
Considered treating "TCGSniperCore" as a file name, but it didn't exist.
I have tried the following:
Ensuring both projects target .netcore2.2
Setting the Agent pool to Hosted VS2017 in Azure DevOps
Setting the BuildConfiguration variable to release
Reproducing on my local machine. I cannot. The solution builds fine.
Why is it looking for the assembly in /debug and not /release?
I found that it looks for the .dll based on the file path specified in the .csproj file. Edit the file (I used VS Code) and add/modify the hint path with $(configuration).
Before:
<ItemGroup>
<Reference Include="TCGSniperCore">
<HintPath>..\tcgsnipercore\bin\Debug\netcoreapp2.2\TCGSniperCore.dll</HintPath>
</Reference>
</ItemGroup>
After:
<ItemGroup>
<Reference Include="TCGSniperCore">
<HintPath>..\tcgsnipercore\bin\$(configuration)\netcoreapp2.2\TCGSniperCore.dll</HintPath>
</Reference>
</ItemGroup>
Thanks #D.J.

Restore nuget packages in msbuild 15 project

I'd like to restore the nuget packages from a private feed (vsts internal feed) in a solution consisting of msbuild 15 projects, and subsequently build (and pack) the projects.
I'm using the VS 2017 hosted agent which I need to build.
I've tried restoring with msbuild with (the deprecated) package restore enabled. This results in no packages being restored. The relevant part of the logs:
2017-04-03T12:21:23.5543508Z ##[warning]The 'Restore NuGet Packages' option is deprecated. To restore NuGet packages in your build, add a NuGet Installer task to your build definition.
2017-04-03T12:21:23.5803410Z ##[command]"C:\LR\MMS\Services\mms\TaskAgentProvisioner\Tools\agents\2.115.0\externals\nuget\NuGet.exe" restore "C:\a\1\s\mysolution.sln" -NonInteractive
2017-04-03T12:21:24.5231560Z MSBuild auto-detection: using msbuild version '4.0' from 'C:\Windows\Microsoft.NET\Framework\v4.0.30319'.
I've tried restoring with the nuget installer task. This fails with
2017-04-03T12:21:05.3231625Z [command]C:\a_tasks\NuGetInstaller_333b11bd-d341-40d9-afcf-b32d5ce6f23b\0.2.29\node_modules\nuget-task-common\NuGet\3.5.0\NuGet.exe restore -NonInteractive C:\a\1\s\mysolution.sln -Verbosity Detailed -msbuildversion 15
2017-04-03T12:21:07.5100892Z NuGet Version: 3.5.0.1938
2017-04-03T12:21:07.8293660Z System.AggregateException: One or more errors occurred.
---> NuGet.CommandLine.CommandLineException: Failed to load msbuild Toolset
---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Build, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
note that I pass in msbuildversion -15 as additional argument, but it seems nuget tries to load msbuild 14.
I've tried restoring with the dontnet cli dotnet restore. This fails with
2017-04-03T12:21:08.3424716Z [command]C:\Program Files\dotnet\dotnet.exe restore C:\a\1\s\path\to\my\csproj
2017-04-03T12:21:12.8146350Z Restoring packages for C:\a\1\s\path\to\my\csproj...
2017-04-03T12:21:12.8146350Z C:\Program Files\dotnet\sdk\1.0.0\NuGet.targets(97,5): error : Unable to load the service index for source https://myvstsaccount.pkgs.visualstudio.com/_packaging/Toolsfeed/nuget/v3/index.json. [C:\a\1\s\path\to\my\csproj]
2017-04-03T12:21:12.8146350Z C:\Program Files\dotnet\sdk\1.0.0\NuGet.targets(97,5): error : Response status code does not indicate success: 401 (Unauthorized). [C:\a\1\s\path\to\my\csproj]
2017-04-03T12:21:12.8176375Z ##[error]Dotnet command failed with non-zero exit code: 1.
The nuget.config in my solution directory is
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="VSTS Tools Feed" value="https://myvstsaccount.pkgs.visualstudio.com/_packaging/Toolsfeed/nuget/v3/index.json" />
</packageSources>
<apikeys>
<add key="https://myvstsaccount.pkgs.visualstudio.com/_packaging/Toolsfeed/nuget/v3/index.json" value="<A PAT generated from an account with access to the feed>" />
</apikeys>
</configuration>
and the logs of the tasks show that the config is used.
Locally package restore works fine from VS, or with the nuget cli of nuget 4.0.
What task should I use to restore packages for msbuild 15 projects, and how can I configure authentication?
Restoring nuget packages defined as PackageReference elements in csproj project definitions requires nuget 4.0, which isn't included on the hosted build agents.
You can work around this restriction by including the nuget 4.0 binary in your source control tree, and referring to that binary within the package restore task as a custom NuGet version.
For example, when you include the nuget 4.0 binary in a file called nuget4.0.exe in the root directory of your source tree, you can specify the path as $(Build.SourcesDirectory)/nuget4.0.exe.
And there is a relate question here for you to refer.

NuGet - install.ps1 does not get called

I'm trying to create my first NuGet package. I don't know why my install.ps1 script does not get called. This is directory structure
--Package
|
- MyPackage.nuspec
- tools
|
- Install.ps1
- some_xml_file
I build package using this command line
nuget.exe pack MyPackage.nuspec
When I Install-Package from VS Package Manager Console install.ps1 does not get called.
I thought that maybe I had some errors in script and that's the reason so I commented out everything but
param($installPath, $toolsPath, $package, $project)
"ECHO"
But I don't see ECHO appearing in Package Manager Console. What can be wrong?
Install.ps will only be invoked if there is something in the \lib and/or \content folder, not for a "tools only" package, though. See here:
The package must have files in the content or lib folder for Install.ps1 to run. Just having something in the tools folder will not kick this off.
Use the Init.ps1 instead (however, this will be executed every time the solution is opened).
Install.ps1 (and Uninstall.ps1) are no longer called in v3, but you can use Init.ps1. See here:
Powershell script support was modified to no longer execute install
and uninstall scripts, but init scripts are still executed. Some of
the reasoning for this is the inability to determine which package
scripts need to be run when not all packages are directly referenced
by a project.
An alternative to the install script can sometimes be a package targets file. This targets file is automatically weaved into the project file (csproj, ...) and gets called with a build.
To allow Nuget to find this targets file and to weave it in, these two things are mandatory:
the name of the targets file must be <package-name>.targets
it must be saved in the folder build at the top level of the package
If you like to copy something to the output folder (e.g. some additional binaries, like native DLLs) you can put these binaries into the package under folder binaries and use this fragment in the targets file for the copying:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyBinaries" BeforeTargets="BeforeBuild">
<CreateItem Include="$(MSBuildThisFileDirectory)..\binaries\**\*.*">
<Output TaskParameter="Include" ItemName="PackageBinaries" />
</CreateItem>
<Copy SourceFiles="#(PackageBinaries)"
DestinationFolder="$(OutputPath)\%(RecursiveDir)"
SkipUnchangedFiles="true"
OverwriteReadOnlyFiles="true"
/>
</Target>
</Project>