Copy client files when publishing - asp.net-core

On a Net Core 7 web application I need to build a few client scripts (JS and LESS).
The scripts are in "./approot" and when I run the command npm run build this is done:
Build the files in "./approot" and save the output to "./approot/dist"
Delete the folder "./webroot" with all its contents.
Create a new "./webroot" and copy all files from "./approot/dist" to "./webroot"
So I have the following on project's .csproj file:
<Target Name="Build Client" AfterTargets="Build">
<Exec Command="npm install" />
<Exec Command="npm run build" />
<ItemGroup>
<Content Include="webroot\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Target>
When I publish the application steps (1) and (2) are done.
However the "./webroot" folder is not copied to publish folder.
So when I upload the web application to the server the client files are not found.
What am I doing wrong?
UPDATE The only way I am able to make this work is using:
<Target Name="Copy Webroot" BeforeTargets="AssignTargetPaths" DependsOnTargets="PrepareForPublish">
<Exec Command="npm install" />
<Exec Command="npm run build" />
<ItemGroup>
<Content Include="webroot/**" CopyToPublishDirectory="Always" />
</ItemGroup>
</Target>
I also kept the following so that Client is build when debugging:
<Target Name="Build Client" AfterTargets="Build">
<Exec Command="npm install" />
<Exec Command="npm run build" />
<ItemGroup>
<Content Include="webroot\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Target>
The problem is when I publish the application I see the client being build twice.
How to solve this?

Related

Copying entire directory using MSBuild

I have the following on an ASP.NET Core 3.1 application:
<Target Name="OnBuild" BeforeTargets="Build">
<Exec WorkingDirectory="approot" Command="npm run build --prod" />
<Copy SourceFiles="approot\dist" DestinationFolder="wwwroot" />
</Target>
When I build I get an error:
The source file "approot/dist" is actually a directory.
The "Copy" task does not support copying directories.
How can I copy the directory approot\dist to wwwroot using MSBuild?
Try this:
<Target Name="OnBuild" BeforeTargets="Build">
<ItemGroup>
<Folder Include="**\approot\**\*.*" />
</ItemGroup>
<Copy SourceFiles="#(Folder)" DestinationFolder="wwwroot\%(RecursiveDir)"></Copy>
</Target>

Creating Bootstrapper Package when all prerequisistes are not in the same root directory setup.exe

I am new to creating Bootstrapper packages. Currently I created Bootstrapper package in which all prerequisistes (VC++, IPP, Windows Installer 3.1, application.mxi) will be inside one single folder and setup.exe will be located outside. For this, I kept product.xml which has product code details for all prerequisites and en folder which has package.xml in the root directory (Bootstrapper\Packages\Dependencies). Actually the problem that I am facing is that, the 'displayname' which is generic for all prerequisites. I want the displayname for list all missed out prerequisites while installing. If I keep all prerquisites in the same root directory of setup.exe with separate product.xml and en folder for each prerequisite, then it shows the displayname properly. But I need folder structure is like setup.exe should be outside the prerequisites. Is there any possibility not to keep product.xml in the root directory of setup.exe?
<Project DefaultTargets="DoPostBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<PropertyGroup>
<MSIName>Test</MSIName>
<MSIFile>$(MSIName).msi</MSIFile>
<DeploymentPath>D:\Test</DeploymentPath>
<TargetPath>$(DeploymentPath)\$(MSIName)</TargetPath>
<BootstrapperPath>D:\Bootstrapper</BootstrapperPath>
<BootstrapperPackagesPath>$(BootstrapperPath)\Packages</BootstrapperPackagesPath>
</PropertyGroup>
<Target Name="CreateTargetDirectory">
<Exec Command="rmdir $(MSIName) /s /q" WorkingDirectory="$(DeploymentPath)" />
<Exec Command="md $(MSIName)" WorkingDirectory="$(DeploymentPath)" />
</Target>
<Target Name="CopyMSI" DependsOnTargets="CreateTargetDirectory">
<copy SourceFiles=".\Test\Release\Test.msi" DestinationFiles="$(TargetPath)\$(MSIFile)" />
</Target>
<Target Name="MakeLinks" DependsOnTargets="CreateTargetDirectory">
<Exec Command="md $(TargetPath)\IPP6_0" />
<Exec WorkingDirectory="$(TargetPath)\IPP6_0" Command="mklink /H ipp_runtime_6_0_x86.msi "
$(BootstrapperPackagesPath)\IPP6_0\ipp_runtime_6_0_x86.msi"" />
<Exec Command="md $(TargetPath)\vcredist_x86_2005" />
<Exec WorkingDirectory="$(TargetPath)\vcredist_x86_2005" Command="mklink /H vcredist_x86.exe "
$(BootstrapperPackagesPath)\vcredist_x86_2005\vcredist_x86.exe"" />
</Target>
<ItemGroup>
<BootstrapperFile Include="IPP.Runtime.6.0.x86">
<ProductName>IPP 6.0</ProductName>
</BootstrapperFile>
<BootstrapperFile Include="Microsoft.Visual.C++.8.0.x86">
<ProductName>VC++ 2005 Runtime</ProductName>
</BootstrapperFile>
</ItemGroup>
<Target Name="BuildBootstrapper" DependsOnTargets="CopyMSI;MakeLinks">
<GenerateBootstrapper
ApplicationFile="$(MSIFile)"
ApplicationName="Test"
BootstrapperItems="#(BootstrapperFile)"
ComponentsLocation="Absolute"
ComponentsUrl="($TargetPath)"
CopyComponents="false"
Culture="en"
Path="$(BootstrapperPath)"
OutputPath="$(DeploymentPath)"/>
</Target>
<Target Name="DoPostBuild" DependsOnTargets="BuildBootstrapper" />
</Project>
}

How to publish additional files using msbuild file and TeamCity?

I'm using a msbuild file, TeamCity and Web Deploy to deploy my siteand everything works just fine, for the files included in the Visual Studio csproj file. In addition to these files I want to publish a couple of more files such as license files etc depending on environment.
This is my build file DeployToTest.proj:
<Project DefaultTargets="Deploy" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<ItemGroup>
<LicenseSourceFiles Include="License.config"/>
<RobotSourceFile Include="robots.txt" />
</ItemGroup>
<Target Name="Build">
<Message Text="Starting build" />
<MSBuild Projects="..\..\WebApp.sln" Properties="Configuration=Test" ContinueOnError="false" />
<Message Text="##teamcity[buildNumber '$(FullVersion)']"/>
<Message Text="Build successful" />
</Target>
<Target Name="Deploy" DependsOnTargets="Build">
<Copy SourceFiles="#(LicenseSourceFiles)" DestinationFolder="..\..\wwroot"></Copy>
<Copy SourceFiles="#(RobotSourceFile)" DestinationFolder="..\..\wwwroot"></Copy>
<Message Text="Started deploying to test" />
<Exec Command="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe ..\..\wwwroot\WebApp.csproj /property:Configuration=Test /t:MsDeployPublish /p:MsDeployServiceUrl=99.99.99.99;DeployIisAppPath=MySite;username=user;password=pass;allowuntrustedcertificate=true" />
<Message Text="Finished deploying to test" />
</Target>
</Project>
As you can see I tried to copy the license.config and robots.txt without any luck.
This .proj file is selected as the 'Build file path' in TeamCity.
Any suggestions on how I can accomplish this?
To solve this problem it may be worth executing the build script with the verbosity set to the 'detailed' or 'diagnostic' level. That should tell you exactly why the copy step fails.
However one of the most likely problems could be the fact that the script is using relative file paths, which depend on the working directory being set to the correct value. For build scripts I prefer use absolute paths to prevent any file path problems.
To get the absolute path you can use the MSBuildProjectDirectory property. The value of this property points to the path of the directory containing the currently executing MsBuild script. With that you can change your MsBuild script like this:
<Project DefaultTargets="Deploy" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<BaseDir>$(MSBuildProjectDirectory)</BaseDir>
</PropertyGroup>
<ItemGroup>
<LicenseSourceFiles Include="$(BaseDir)\License.config"/>
<RobotSourceFile Include="$(BaseDir)\robots.txt" />
</ItemGroup>
<Target Name="Build">
<Message Text="Starting build" />
<MSBuild Projects="$(BaseDir)\..\..\WebApp.sln" Properties="Configuration=Test" ContinueOnError="false" />
<Message Text="##teamcity[buildNumber '$(FullVersion)']"/>
<Message Text="Build successful" />
</Target>
<Target Name="Deploy" DependsOnTargets="Build">
<Copy SourceFiles="#(LicenseSourceFiles)" DestinationFolder="$(BaseDir)\..\..\wwroot"></Copy>
<Copy SourceFiles="#(RobotSourceFile)" DestinationFolder="$(BaseDir)\..\..\wwwroot"></Copy>
<Message Text="Started deploying to test" />
<Exec Command="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe ..\..\wwwroot\WebApp.csproj /property:Configuration=Test /t:MsDeployPublish /p:MsDeployServiceUrl=99.99.99.99;DeployIisAppPath=MySite;username=user;password=pass;allowuntrustedcertificate=true" />
<Message Text="Finished deploying to test" />
</Target>
</Project>
Now this should fix the problem if there is indeed a problem with the relative file paths.
Solution was to change settings for the web project in Visual Studio. Under Package/Publish Web i set 'Items to deploy' to 'All files in this project folder'. I then added a filter to remove all .cs files and other unwanted files.

Cannot execute custom code in *.csproj after Compile but before Build

This code fails when run from VisualStudio 2010 csproj file.
Please help.
<PropertyGroup>
<IntelliLockLocation>"C:\Program Files (x86)\Eziriz\IntelliLock\INTELLILOCK.exe"</IntelliLockLocation>
<IntelliLockProject>"C:\Downloads\intellilock.ilproj"</IntelliLockProject>
</PropertyGroup>
<Target Name="AfterCompile">
<Exec Command="$(IntelliLockLocation) -project $(IntelliLockProject) -file "$(ProjectDir)$(IntermediateOutputPath)$(TargetFileName)" -targetfile "$(ProjectDir)$(IntermediateOutputPath)$(TargetFileName)"" />
</Target>
The solution is to use custom Microsoft.VisualStudio.Tools.Office.targets without problematic targets.
<Import Project="..\Microsoft.VisualStudio.Tools.Office.targets" />
<Target Name="AfterCompile">
<Exec Command="$(IntelliLockLocation) -project $(IntelliLockProject) -file "$(ProjectDir)$(IntermediateOutputPath)$(TargetFileName)" -targetfile "$(ProjectDir)$(IntermediateOutputPath)$(TargetFileName)" -snkeypair "$(ProjectDir)$(AssemblyOriginatorKeyFile)" -snpassword *****" />
</Target>

MSBuild and creating ZIP files

Here is my build script:
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<PropertyGroup>
<!-- Path where the solution file is located (.sln) -->
<ProjectPath>W:\Demo</ProjectPath>
<!-- Location of compiled files -->
<DebugPath>W:\Demo\bin\Debug</DebugPath>
<ReleasePath>W:\Demo\bin\Release</ReleasePath>
<!-- Name of the solution to be compiled without the .sln extension --> <ProjectSolutionName>DemoTool</ProjectSolutionName>
<!-- Path where the nightly zip file will be copyd -->
<NightlyBuildPath>W:\Nightly_Builds\Demo</NightlyBuildPath>
<!-- Name of the nighly zip file (YYYYMMDD_NightlyZipName.zip, date added automatically) -->
<NightlyZipName>Demo</NightlyZipName>
</PropertyGroup>
<ItemGroup>
<!-- All files and folders from ./bin/Debug or ./bin/Release what will be added to the nightly zip -->
<DebugApplicationFiles Include="$(DebugPath)\**\*.*" Exclude="$(DebugPath)\*vshost.exe*" />
<ReleaseApplicationFiles Include="$(ReleasePath)\**\*.*" Exclude="$(ReleasePath)\*vshost.exe*" />
</ItemGroup>
<Target Name="DebugBuild">
<Message Text="Building $(ProjectSolutionName) Debug Build" />
<MSBuild Projects="$(ProjectPath)\$(ProjectSolutionName).sln" Targets="Clean" Properties="Configuration=Debug"/>
<MSBuild Projects="$(ProjectPath)\$(ProjectSolutionName).sln" Targets="Build" Properties="Configuration=Debug"/>
<Message Text="$(ProjectSolutionName) Debug Build Complete!" />
<CallTarget Targets="CreateNightlyZip" />
</Target>
<Target Name="CreateNightlyZip">
<PropertyGroup>
<StringDate>$([System.DateTime]::Now.ToString('yyyyMMdd'))</StringDate>
</PropertyGroup>
<MakeDir Directories="$(NightlyBuildPath)"/>
<Zip Files="#(DebugApplicationFiles)"
WorkingDirectory="$(DebugPath)"
ZipFileName="$(NightlyBuildPath)\$(StringDate)_$(NightlyZipName).zip"
ZipLevel="9" />
</Target>
</Project>
My script works perfectly, only there is one strange problem. When i build a project first time and there is no \bin\Debug folder and its created during the build, but the ZIP file still comes empty. Running the build script second time when the \bin\Debug folder is now in place with builded files then the file are added to the ZIP.
What could be the problem that running script first time the ZIP file is empty?
The problem is in the DebugApplicationFiles item collection. It is created before the build is invoked. Move the DebugApplicationFiles into CreateNightlyZip target. Update your script this way:
<Target Name="CreateNightlyZip">
<PropertyGroup>
<StringDate>$([System.DateTime]::Now.ToString('yyyyMMdd'))</StringDate>
</PropertyGroup>
<ItemGroup>
<DebugApplicationFiles Include="$(DebugPath)\**\*.*" Exclude="$(DebugPath)\*vshost.exe*" />
</ItemGroup>
<MakeDir Directories="$(NightlyBuildPath)"/>
<Zip Files="#(DebugApplicationFiles)"
WorkingDirectory="$(DebugPath)"
ZipFileName="$(NightlyBuildPath)\$(StringDate)_$(NightlyZipName).zip"
ZipLevel="9" />
</Target>
If powershell 5.0 or greater is available, you could use powershell command directly.
<Target Name="Zip" BeforeTargets="AfterBuild">
<ItemGroup>
<ZipFiles Include="$(OutDir)release\file1.exe" />
<ZipFiles Include="$(OutDir)release\file2.exe" />
</ItemGroup>
<Exec Command="PowerShell -command Compress-Archive #(ZipFiles, ',') $(OutDir)release\zippedfiles.zip" />
</Target>
Should you wish to zip a whole folder for 'xcopy deploy', since MSBuild 15.8 there is a simple way - the ZipDirectory build task.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="ZipOutputPath" AfterTargets="Build">
<ZipDirectory
SourceDirectory="$(OutputPath)"
DestinationFile="$(OutputPath)\..\$(AssemblyName).zip"
Overwrite=="true" />
</Target>
</Project>
[1] https://learn.microsoft.com/en-us/visualstudio/msbuild/zipdirectory-task?view=vs-2019