Similar to PipelineCopyAllFilesToOneFolderForMsdeployDependsOn for UWP packaging - visual-studio

ITNOA
As you can see in Web Deployment Tool (MSDeploy) : Build Package including extra files or excluding specific files and Adding Custom Files to an MSDeploy Package msbuild desired target has property event that name is PipelineCopyAllFilesToOneFolderForMsdeployDependsOn for handling copy desired files into process.
I need something similar for UWP, to add custom file copy to AppX folder during packaging and f5 click in Visual Studio in .csproj file.
thanks

After many working I found solution, AppX Packaging is coordinate from Microsoft.AppxPackage.Targets that exists in Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VisualStudio\v17.0\AppxPackage and all important target for packaging and running (f5 in Visual Studio) exists here.
As you can see in this file, Microsoft create some blank target between important target in build and packaging pipeline, so you can use override these blank targets very cleanly to control procedure of building and packaging AppX, for example you can override blow targets
<!-- Override to specify actions to happen before generating project PRI file. -->
<Target Name="BeforeGenerateProjectPriFile" />
or
<!-- Override to specify actions to happen after generating project PRI file. -->
<Target Name="AfterGenerateProjectPriFile" />
or ...
So for adding custom files into packaging I override BeforeGenerateProjectPriFile target and for adding file, I used PackagingOutputs ItemGroup for adding my file like below
<Target Name="BeforeGenerateProjectPriFile">
<ItemGroup>
<PackagingOutputs Include="$(MSBuildProjectDirectory)\$(OutputPath)$(AssemblyName).exe.config">
<OutputGroup>ContentFilesProjectOutputGroup</OutputGroup>
<TargetPath>$(AssemblyName).exe.config</TargetPath>
<ProjectName>$(ProjectName)</ProjectName>
</PackagingOutputs>
</ItemGroup>
</Target>
If you want this approach in practice, I used this technique in linphone-windows10

Related

Build target in the Publish Profile is not executing even if the Publish is successful

I have a publish profile Staging.pubxml created for a console project (.NET Core 2.1), as follows:
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Staging</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PublishDir>bin\Release\netcoreapp2.1\publish\</PublishDir>
<SelfContained>false</SelfContained>
<_IsPortable>true</_IsPortable>
</PropertyGroup>
<Target Name="CustomActionsAfterPublish" AfterTargets="AfterPublish">
<Message Text="First occurrence" Importance="high" />
</Target>
</Project>
When I publish it (via VS2019); publish completes successfully. Yet I'am not seeing the text: First occurrence in the output window.
In VS, MSBuild output verbosity is set to Diagnostic.
Am I doing this wrong?
Am I doing this wrong?
1.Hi friend, the .pubxml file is not a good place to define custom Target.
According to your target name, you want to run the target after build target. For this situation: always we define the custom target in project file. Please try right-click your project and choose edit xxx.csproj, and add the target into it. Then reload the project and publish, then you can find the First occurrence message in the build output.
And after my test, in.csproj file, the target can't be named AfterBuild, you can change it to:
<Target Name="CustomTargetName" AfterTargets="build">
<Message Text="First occurrence" Importance="high" />
</Target>
2.Also, the way you use can work in VS2019 though we don't suggest adding it in .pubxml. But it indeed works. For the reason why you can't get the message in output window, please check if the Staging.pubxml is really called during the publish process.
(Change the value of the PublishDir to another folder, and publish it again, check if the project is published to new directory, then you'll find if the xxx.pubxml is used)
Update:
According to your .pubxml file, your project is a .net core console app instead of a asp.net core web app. This makes the difference!
I test it in both VS2017 and VS2019, and find the target works well in asp.net web app but not .net core console one. I believe for those non-web app, this kind of after publish target may not be supported.
And please check these two official documents I found:
Asp.net core: Run a target before or after publishing
.net core: Deploy .net core apps with VS
I can't find any custom-target-related info in the .net core document. So I'm afraid it might be not supported by design.
Update2:
Actually your original need is to add CopyFiles target to publish process. So I assume what you really want is to copy sth to Publish Folder after Publish process or copy sth from Publish Folder to target folder.
Though the after publish target is not supported in .net core console apps. We have corresponding workarounds:
To copy sth to Publish Folder after Publish:
For this situation, you can add a after build target to copy the files to Publish folder before publish process. I think it works for this situation:
<Target Name="CustomTarget" AfterTargets="build">
<ItemGroup>
<MySourceFiles Include="xxx\pathToTheFolderWhereYourFilesAre\*.*"/>
</ItemGroup>
<Copy
SourceFiles="#(MySourceFiles)"
DestinationFolder="$(ProjectDir)bin\Release\netcoreapp2.1\publish\"
/>
</Target>
To copy sth from Publish Folder to target folder:
For .net core console app, actually the so-called publish process is to copy files from obj folder to publish folder. See this screenShot:
Go Tools=>Options=>Project and Solutions=>Build and Run to change the build output verbosity to Detailed and you can see details in build and publish process in VS.
That's why I suggest you can Go Project=>Properties=>build events=>post-build events to use a xcopy command to copy the files to your destination folder.(Or you can use a script like above, remember to change the source path and destination path). When we want to copy the files in publish folder, actually we're trying to copy the files from obj folder. So do something after build process is enough! Not need to do it after publish process.

How do I include webjob files while debugging locally but exclude when publishing a web package?

I'm using Visual Studio 2017 and have a solution with several web projects and webjob projects.
There are some files that I want to include when running locally in the development environment that I want to exclude from being deployed as part of a web publishing package.
I'm attempting to use the process described here http://sedodream.com/2010/05/01/WebDeploymentToolMSDeployBuildPackageIncludingExtraFilesOrExcludingSpecificFiles.aspx and elsewhere, which is:
<ItemGroup>
<ExcludeFromPackageFiles Include="connectionstrings.config">
<FromTarget>Project</FromTarget>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</ExcludeFromPackageFiles>
</ItemGroup>
This works perfectly for my web projects - meaning that when building the connectionstrings.config file is copied to my bin\ directory and not included as part of the web deployment package - whereas when implemented in my webjob projects the file is copied to my bin\ directory but also included in the deployment package.
In the msbuild output I see:
Copying file from "C:\Users\me\Documents\Projects\myapp\myapp\webjob1\connectionstrings.config" to "bin\ProdBuildCfg\connectionstrings.config".
which is what I want because it allows me to run/debug locally, and also:
Copying C:\Users\me\Documents\Projects\myapp\myapp\webjob1\bin\ProdBuildCfg\connectionstrings.config to obj\ProdBuildCfg\Package\PackageTmp\app_data\jobs\continuous\webjob1\connectionstrings.config.
which demonstrates the problem - connectionstrings.config is still being copied to the package directory for subsequent publishing/deployment.
The process described in the above article and others applies to web projects, and they indicate you should place the <ItemGroup> under the
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
line of the project file. Webjob projects don't include that line but rather have something resembling:
<Import Project="..\packages\Microsoft.Web.WebJobs.Publish.1.0.13\tools\webjobs.targets" Condition="Exists('..\packages\Microsoft.Web.WebJobs.Publish.1.0.13\tools\webjobs.targets')" />
I suspect the problem relates to targets - either my project file doesn't include the proper <Import Project="...*.targets')" /> line or I'm not at the right spot in the file.
Next I tried the method mentioned here How do I include webjob files while debugging locally but exclude when publishing a web package?:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<ExcludeFilesFromDeployment>connectionstrings.config</ExcludeFilesFromDeployment>
</PropertyGroup>
I have the connectionstrings.config Build Action set to None and Copy to output directory set to Always (my understanding is that action that results from the Copy to output directory setting is distinctly different from the actions associated with packaging/deployment). Same result. (I've ensured I'm in the right <PropertyGroup> for my build configuration.
Note: I'm deploying either by right-clicking the project in VS and selecting "Publish as Azure webjob" or using an msbuild command to publish like msbuild myproj.csproj /p:DeployOnBuild=true /p:Configuration=Release /p:PublishProfile="Prod" /p:VisualStudioVersion=15.0 /p:Password=
How do I include webjob files while debugging locally but exclude when publishing a web package?
To my knowledge, if you do not want to publish any file, you just need to set the file property to "copy to output directory as DO NOT COPY". This way when you will package the application that particular file will not be part of package and will never be on Azure.
Update:
Unfortunately that setting prevents the file from being copied to the
output directory which means I can’t run or debug locally.
When you debugging the project, you can set the "copy to output directory" as "Copy always". When you want to deploy the project, you can manually clean the build and change the value to DO NOT COPY.
If you do not want to do all those manually, I would like provide you a workaround, hope this can help you.
To accomplish this, unload your project. Then at the very end of the project , just before the end-tag, place below scripts:
<Target Name="ExcludeFileFromPackage" BeforeTargets="PipelineCopyAllFilesToOneFolderForMsdeploy">
<Message Text="Delete the connectionstrings.config from Obj folder to exculde this file in the package directory" />
<Delete Files="$(ProjectDir)obj\Release\Package\PackageTmp\connectionstrings.config" />
</Target>
With this target, VS/MSBuild will delete the connectionstrings.config from the obj folder before publish the project as package.

TFS 2017 Build Definition: Packaging Web API Project for deployment

I have a Visual Studio solution that contains four projects:
1 Desktop app;
1 Windows Service;
2 Web API projects.
These projects have been migrated from VS2010 -> 2013 -> 2017. I've removed/edited as much legacy stuff as I recognise.
The solution builds fine in 2017.
I wish to only build one of the Web API projects, generate a deployment package, and publish the package as an artifact. A release definition is going to use WinRM to deploy the package on a Windows Server 2012 system running IIS.
In my build definition I have a MSBuild task.
The parameters of this task are as follows:
Project is set to the path of my webAPI .csproj in TFS source control
Platform is set to "AnyCPU" - ("Any CPU" doesn't work.. its a known (old) issue)
Configuration is "Release"
MSBuild arguments are:
/p:DeployOnBuild=true /p:WebPublishMethod=Package
/p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation=$(Build.ArtifactStagingDirectory)\webapi.zip
Clean is set to true
The build completes successfully, however the webapi.zip package that is produced contains a massive folder structure:
C:\agent2_work\27\a\webapi.zip\Content\C_C\agent2_work\27\s\MyProduct.WebApi\obj\release\Package\PackageTmp
Questions:
Why is it packing this full path? (c:\agent2_work is my build agent's directory)
How do I change it?
It's the expected behavior, it's based on your Package Location. If you publish the project in VS, you will find the similar folder structure. See Create a Web Deployment Package in Visual Studio for details. And this thread for your reference.
However you can change the folder structure with publish profile used in MSBuild Arguments. Following below steps to do that:
1, Create a publish profile.
To create a web deploy package in VS you
will first create a publish profile for that. When you do this, a
.pubxml file will be created for you under
Properties\PublishProfiles. This is your publish profile file, its an MSBuild file. You can customize your publish process by editing
this file. We will modify this file in order to update these paths
in the package.
2, Edit the .pubxml file for the profile and add the following before
the closing </Project> tag. (Create the target AddReplaceRuleForAppPath, and inject that into the package process by adding it to PackageDependsOn property. Once this target is executed it will add a replace rule into the MSDeployReplaceRules item group.)
<PropertyGroup>
<PackagePath Condition=" '$(PackagePath)'=='' ">WebApi</PackagePath>
<EnableAddReplaceToUpdatePacakgePath Condition=" '$(EnableAddReplaceToUpdatePacakgePath)'=='' ">true</EnableAddReplaceToUpdatePacakgePath>
<PackageDependsOn>
$(PackageDependsOn);
AddReplaceRuleForAppPath;
</PackageDependsOn>
</PropertyGroup>
<Target Name="AddReplaceRuleForAppPath" Condition=" '$(EnableAddReplaceToUpdatePacakgePath)'=='true' ">
<PropertyGroup>
<_PkgPathFull>$([System.IO.Path]::GetFullPath($(WPPAllFilesInSingleFolder)))</_PkgPathFull>
</PropertyGroup>
<!-- escape the text into a regex -->
<EscapeTextForRegularExpressions Text="$(_PkgPathFull)">
<Output TaskParameter="Result" PropertyName="_PkgPathRegex" />
</EscapeTextForRegularExpressions>
<!-- add the replace rule to update the path -->
<ItemGroup>
<MsDeployReplaceRules Include="replaceFullPath">
<Match>$(_PkgPathRegex)</Match>
<Replace>$(PackagePath)</Replace>
</MsDeployReplaceRules>
</ItemGroup>
</Target>
3, Save the Publish Profile file and check in the changes
4, Enter below MSBuild arguments: (In this example my publish profile name is 1011DP.pubxml)
/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:PublishProfile=1011DP /p:SkipInvalidConfigurations=true /p:PackageLocation=$(Build.ArtifactStagingDirectory)
5, Run the build, then check the folder structure.
To make things a bit easier I just created a nuget package that performs these steps automatically for you. See https://www.nuget.org/packages/SharpSvn.ShortMSDeployWebContentPath
Just installing this in your web application project from Visual Studio will change the long path below 'Contents' with just the single word 'web'

SlowCheetah executes after post-build events

I use SlowCheetah to transform my app.configs. I have a multi-project solution where one of the projects executes a post-build event where the output of the bin is copied elsewhere. I've found that SlowCheetah does it's transforms after the post-build event, so the app.config I'm copying is the pre-transformed version.
Does anyone have a suggestion of how I can execute my copy after the SlowCheetah transforms? Is this going to require that I write a custom build task?
If you are using msbuild 4.0 for building your projects - you can hook to slowcheetah targets with new AfterTargets BeforeTargets attributes.
I dont know what exactly target name you want to hook after but this code could gave you base concept how to do this
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Some_Target_Name" AfterTargets="TransformAllFiles" >
<Message Text="= Script here will run after SlowCheetah TransformAllFiles ="/>
</Target>
<Project>
Edited: I installed SlowCheetah and found that AfterTargets attribute should be "TransformAllFiles".
Just set up your target dependency AfterTargets="TransformAllFiles"
Alexey's answer leads to the correct solution but here it is in full:
Right-click your project and select Unload Project
Now right-click the project and select Edit [your project name].csproj
Scroll to the bottom and uncomment the target named AfterBuild and add this attribute AfterTargets="TransformAllFiles"
Move your post build actions into this target using the Exec command:
An example:
<Target Name="AfterBuild" AfterTargets="TransformAllFiles">
<Exec Command="ECHO Hello PostBuild World!" />
</Target>
I have bumped into this problem too... decided to update to latest version of SlowCheetah (current 2.5.8), and this problem appears to have been fixed! No more problems using post-build events to deploy a project with transformed XML!
After the NuGet package upgrade process, I had a strange issue, though... transforms were no longer happening. Editing the project like Naeem Sarfraz suggested, I have found that the SlowCheetah's PropertyGroup section was placed at the end of the .csproj.
It was just a matter of moving it to the top, near the other PropertyGroup sections, and now it works like a charm!
If you need to copy/move other .config files (other than web.config) around after the build before publishing here is how it can be done with Visual Studio 2013 (I didn't test it on earlier versions). This section can be added at the end of the .csproj file right before the closing tag </Project> and it'll be fired just before MSDeploy starts the Publishing process.
<Target Name="MoveConfigFile" BeforeTargets="MSDeployPublish">
<Move
SourceFiles="$(IntermediateOutputPath)Package\PackageTmp\ThirdPartyApp.config"
DestinationFolder="$(IntermediateOutputPath)Package\PackageTmp\bin"
OverwriteReadOnlyFiles="true"
/>
</Target>
The company I work for purchased a third party product that needs to have a .config files in the bin folder along with its assembly in order to work.
At the same time we need to process the product's .config file and be able to move it to the bin folder after transformations.
The $(IntermediateOutputPath)Package\PackageTmp folder contains the whole application that will be copied over the target server.

Use different pre-build events for different build configurations in Visual Studio

Is it possible to use different pre-build events for different build configurations in Visual Studio?
For example, I'd like both a release configuration for a beta & live system and have the relevant app.[type].config get copied to app.config before it is compiled.
At the moment the configuration settings are baked into the .settings file, using the settings from the default app.config file.
Or just put the Condition on your target ... eg.,
Condition="'$(Configuration)' == 'Debug'"
.. or on your task.
If you're using Visual Studio VB/C# simple post build events, you can hand-edit the project file to put such conditions on the PreBuildEvent/PostBuildEvent property tags; and repeat the tags for Release.
Dan (msbuild dev)
You can do this in a couple of ways, depending on your exact situation:
Option 1: Check the $(ConfigurationName) variable in your pre-build script, like so:
IF EXISTS $(ProjectDir)app.$(ConfigurationName).config
COPY $(ProjectDir)app.$(ConfigurationName).config $(ProjectDir)app.config
Option 2: Add a "BeforeCompile" MSBuild target to your project file:
<Target Name="BeforeBuild">
<!-- MSBuild Script here -->
</Target>
Option 3: Use configuration file transformations; this VSIX plug-in adds the web.config transform features to non-web projects. These are XSLT files that let you rewrite your config files on build (unlike web projects, where it happens on publish.)
To use different build events for different configuration in visual studio, open the cs proj file of the project. in the pre build section
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Condition="'$(Configuration)'=='Release'" Command="echo Release" />
<Exec Condition="'$(Configuration)'=='Debug'" Command="echo Debug" />
</Target>
The command in "Command" parameter will only execute if this condition is met.

Resources