Visual studio 2017 Excludefoldersfromdeployment but include some subfolder - visual-studio

I was wondering if it's possible to include some sub-folder on publication, of an excluded folder.
Let's assume i have this structure:
/Folder1/
/Folder1/FileX
/Folder1/FileY
/Folder1/SubFolder1/
/Folder1/SubFolder2/
What i want is to exclude the whole Folder1 content, but include only a specific set of sub-folder (in my example SubFolder1).
The Folder1 folder is excluded with the ExcludeFoldersFromDeployment in the .pubxml:
<ExcludeFoldersFromDeployment>Folder1</ExcludeFoldersFromDeployment>

You haven't told us what this .pubxml file is, so there is a limit to what we can help you with.
But in general:
The construct that deals with files and folders in MSBuild is Items.
You want an Item here, not an MSBuild property.
So you could easily use an item to point to a specific sub folder in your build environment like this:
<ItemGroup>
<!-- This will grab all files in SubFolder1 but not recursively -->
<DeployThese Include="/Folder1/SubFolder1/*.*" />
</ItemGroup>
You can then do anything you want with that Item. You could copy the files in it somewhere else, or anything else with them.
The files are accessed later by using #(DeployThese)

I was wondering if it's possible to include some sub-folder on
publication, of an excluded folder.
Yes, it’s possible.
Note: One point we should know, as you’ve used “ExcludeFoldersFromDeployment” element in .pubxml to exclude the entire Folder1 directory. Some deploy actions in .xxproj file may be overwritten or affected by it.
So, to achieve your goal we have to follow two steps:
1. Copy the SubFolder to a new folder (A new folder in $(ProjectDir) can be better)
2. Add the content of SubFolder to publish, and choose the structure you want
Here’s a workaround:
1: Add a PreBuildEvent prorerty in .csproj file.
<PropertyGroup>
<PreBuildEvent>xcopy "$(ProjectDir)/Folder1/SubFolder1" "$(ProjectDir)/NewFolder" /E /Y /I</PreBuildEvent>
</PropertyGroup>
2: Add following markup to .csproj file, it helps publish extra files to publish folder in Asp.net:
<PropertyGroup>
<PipelineCollectFilesPhaseDependsOn>
CustomCollectFiles;
$(PipelineCollectFilesPhaseDependsOn);
</PipelineCollectFilesPhaseDependsOn>
</PropertyGroup>
<Target Name="CustomCollectFiles">
<ItemGroup>
<_CustomFiles Include="NewFolder\**\*" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>MyStructureUnderPublishFolder\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
For this markup, we only need to change two paths to meet our needs.
First:The CustomFiles refers to the folder whose content will be published.
Second:The MyStructureUnderPublishFolder refers to the structure you want under publish folder. If you want a Folder1 which only has a SubFolder in it after deployment, change it to Folder1/SubFolder1, or change it to SubFolder1 if you want a simple Subfolder1 under Publish folder.
More information about adding extra files to publish see here.

Related

MSBuild - want to get the output assembly

I have a .targets file in a folder named .pack I have this:
<PropertyGroup>
<TaskAssembly>$(OutputPath)netstandard2.1\Test.dll</TaskAssembly>
</PropertyGroup>
Why instead of MyProject\bin\Debug\netstandard2.1\MyProject.dll it locates like the below line?
MyProject\.pack\bin\Debug\netstandard2.1\MyProject.dll
Why .pack is there!?
Then wanted to use it with a Using task
<UsingTask
TaskName="brand.ProBuild.Tasks.TestFunction"
AssemblyFile="$(TaskAssembly)"
/>
Defined as inline address, played with slashes, cleared bin/obj, restarted, don't why it can't understand some addresses.
Defined and used several path variables in my targets files, some working correctly and some are troublesome especially when want to use parents or some problems with slashes '/', don't know maybe some addresses are working randomly. But what is wrong with the $(OutputPath) ?!
Visual-studio 2019, .Net Standard 2.1 (It has multiple targets I want to get that specific dll)
You should check in your main project, before the import node like <Import Project=".pack\xxx.targets" />, check whether you defined the outputpath property again like
<outputpath>.pack\bin\Debug\</outputpath>
Suggestion
From your description, you created a custom MSBuild task dll to use its new custom task in another project, first, please make sure that the Test.dll is in the output folder of your project called MyProject.
Then, check whether you have redefined the outputpath before the import xml node.
Like this:
<PropertyGroup>
<outputpath>.pack\bin\Debug\</outputpath>
</PropertyGroup>
..........
<Import Project=".pack\xxx.targets" />
........
<UsingTask
TaskName="brand.ProBuild.Tasks.TestFunction"
AssemblyFile="$(TaskAssembly)"
/>
If so, you should change OutputPath to bin\Debug\.
In addition, if it does not help you, please share the xxx.csproj of project MyProject with us so that we can troubleshoot your issue more quickly.
Update 1
Since you have only one targets file in your project, I suggest you could follow these suggestions:
1) close VS Instance, enter your project folder, delete the .vs hidden folder under the solution folder, bin and obj folder. Then ,restart your project to test again.
2) you can define the correct value in the xxx.csproj file before the imports xml node to force the correct value of outputPath.
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<OutputPath>bin\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<OutputPath>bin\Release\</OutputPath>
</PropertyGroup>
.......
<Import Project="xxx.targets"/>

MSBuild: Copying a list of files into different locations based on file name using the Copy Task

I have a set of customer-specific configuration files that are located in a single Release folder at the time of the build. The file names are something like:
CustomerA_InstanceConfigurationX.config
CustomerA_InstanceConfigurationY.config
CustomerB_InstanceConfigurationX.config
CustomerB_InstanceConfigurationY.config
... etc.
During the build, I want to copy the customer-specific configuration files into a customer-specific Binaries folder:
$(BuildDirectory)\Binaries\Installers\CustomerA\ProductName\
$(BuildDirectory)\Binaries\Installers\CustomerB\ProductName\
So CustomerA_InstanceConfigurationX.config and CustomerA_InstanceConfigurationY.config would go into go into $(BuildDirectory)\Binaries\Installers\CustomerA\ProductName\ and so on.
How can I set the SourceFiles and the DestinationFolder properties to make this happen?
I have the list of Customers as a meta of an Instance property and set the SourceFiles and DestinationFiles around it:
<ItemGroup>
<ConfigFilesToCopy Include="$(BuildDirectory)\stage\InstallerDev\%(Instance.Customer)\Setup\bin\Release\%(Instance.Customer)_*.*" />
<DestionationsForConfigFiles Include="$(BuildDirectory)\Binaries\Installers\%(Instance.Customer)\InstallerDev\" />
</ItemGroup>
<Copy SourceFiles="#(ConfigFilesToCopy)" DestinationFolder="%(DestionationsForConfigFiles.FullPath)" />
That just copies all the customer .config files into all the customer-specific Binaries folder though.
Using the message task, %(Instance.Customer) outputs:
CustomerA
CustomerB
CustomerC.
%(ConfigFilesToCopy.Identity) outputs:
"C:\Builds\AgentX\YYY\INSTALLER_DEV Build\stage\InstallerDev\CustomerA\Setup\bin\Release\CustomerA_InstanceX.config"
"C:\Builds\AgentX\YYY\INSTALLER_DEV Build\stage\InstallerDev\CustomerA\Setup\bin\Release\CustomerA_InstanceY.config"
"C:\Builds\AgentX\YYY\INSTALLER_DEV Build\stage\InstallerDev\CustomerB\Setup\bin\Release\CustomerB_InstanceX.config"
"C:\Builds\AgentX\YYY\INSTALLER_DEV Build\stage\InstallerDev\CustomerB\Setup\bin\Release\CustomerB_InstanceY.config"
Etc.
%(DestionationsForConfigFiles.Identity) outputs:
C:\Builds\Agent8\Five0\INSTALLER_DEV Build\Binaries\Installers\CustomerA\InstallerDev\
C:\Builds\Agent8\Five0\INSTALLER_DEV Build\Binaries\Installers\CustomerB\InstallerDev\
C:\Builds\Agent8\Five0\INSTALLER_DEV Build\Binaries\Installers\CustomerC\InstallerDev\
Etc.
If someone could offer some help on achieving this or had a alternative approach for it, that'd be great. (E.g., I could re-organize the customer-specific configuration files into a customer-specific folders or something.) Thanks a lot in advance!
[** Update Note **: For now, I hard-coded each customer name into a ConfigFilesToCopy list item as well as a DestinationsForConfigFiles item.
<ConfigFilesToCopy Include="$(BuildDirectory)\stage\InstallerDev\CustomerA\Setup\bin\Release\CustomerA_*.*">
<DestionationsForConfigFiles>$(BuildDirectory)\Binaries\Installers\CustomerA\InstallerDev\</DestionationsForConfigFiles>
</ConfigFilesToCopy>
<ConfigFilesToCopy Include="$(BuildDirectory)\stage\InstallerDev\CustomerB\Setup\bin\Release\CustomerB_*.*">
<DestionationsForConfigFiles>$(BuildDirectory)\Binaries\Installers\CustomerB\InstallerDev\</DestionationsForConfigFiles>
</ConfigFilesToCopy>
This works, but I am basically wondering if it's possible to do the same thing without explicitly using the customer name so that I don't have to maintain this list every time we add a new customer.
Make the destination metadata of the files (I changed the paths so it better fits in SO's code box, but the idea is the same):
<Target Name="Copy">
<ItemGroup>
<ConfigFilesToCopy Include="$(SomeDir)\%(Instance.Customer)\%(Instance.Customer)_*.*">
<DestionationsForConfigFiles>$(SomeDir)\Binaries\%(Instance.Customer)</DestionationsForConfigFiles>
</ConfigFilesToCopy>
</ItemGroup>
<Message Text="Source=%(ConfigFilesToCopy.Identity) Dest=%(ConfigFilesToCopy.DestionationsForConfigFiles)" />
</Target>

Copy entire directory to output folder maintaining the folder structure?

I want a specific directory to be copied to output folder ("bin") on every build. I think it can be handled via post build scripts. But I'm not sure how to copy a directory itself. I know how to handle specific files.
For eg, this works for a file:
In
Project > Properties > Build Events> Post Build
COPY "$(SolutionDir)Resources\Release Notes.pdf" "$(TargetDir)"
But suppose I have a directory Template, now I need everything under Template to come to bin folder upon successful build maintaining the folder structure.
I tried this:
COPY "$(SolutionDir)Resources\Template\" "$(TargetDir)"
Only the files in Template directory gets copied this way and not the sub directories and the files inside Template folder. I want the folder Template itself to come inside my output bin folder. In other words, bin should look like:
bin > Template > abc.xxx
xxx.yyy
Subdirectory1 > asd.qwe
zxc.qwe
Subdirectory2 > ...
This could be a duplicate, but I couldn't find a relevant thread. Thanks.
I just added this to my *.csproj file (right click Edit Project File)
<ItemGroup>
<Content Include="MYCUSTOMFOLDER\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
I think for this the directory needs to be on same hierarchy level as *.csproj file or bellow that.
This worked for me. /S is the key which copies everything recursively.
XCOPY "$(SolutionDir)Resources\Template" "$(TargetDir)\Template\" /S
Since I wanted files to be overwritten every time without a prompt, I added a /Y switch as well.
XCOPY "$(SolutionDir)Resources\Template" "$(TargetDir)\Template\" /S /Y
Try XCOPY instead of COPY; e.g.
XCOPY "$(SolutionDir)Resources\Template\" "$(TargetDir)\Template" /s /i /y
More info on XCOPY here...
http://www.computerhope.com/xcopyhlp.htm
Here's an additional solution working on Visual Studio 2019 as of the date of this post. This will copy the folder structure recursively and all files within. Tested on a C++ .vcxproj in a multi-project solution.
First, start by editing your [ .proj / .vcxproj / .csproj ] file. Once open, find your project scoped tag. If you already have ItemGroups within, then paste the code below directly after the existing ones. Otherwise, add it in before the PropertyGroup tags. Then modify the Include & Link parameters for the folder structure you wish to copy to the output path.
<ItemGroup>
<Content Include="..\Assets\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<DeploymentContent>true</DeploymentContent>
<Link>Assets\%(RecursiveDir)\%(Filename)%(Extension)</Link>
</Content>
</ItemGroup>
Note: If you have multiple top level folders, like JS, IMG, BIN, etc., then create a new entry for each one.
The solution by CodingYourLife almost worked for me, but I found out that PreserveNewest was not being respected. I found a solution on the Visual Studio forums that works correctly. My .CSPROJ now looks like this:
<Content Include="assets\**">
<Link>assets\%(RecursiveDir)\%(Filename)%(Extension)</Link>
<TargetPath>assets\%(RecursiveDir)\%(Filename)%(Extension)</TargetPath>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Note: This solution requires Visual Studio 16.10 or newer.
I have a working solution of this question:
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<ItemGroup>
<CommonFont Include="..\common\src\Web\wwwroot\css\fonts\*.*" />
</ItemGroup>
<Copy SourceFiles="#(CommonFont)" DestinationFolder="wwwroot\css\fonts" SkipUnchangedFiles="true" />
</Target>
This is the only solution that worked for me (VS2022, .Net Framework):
<ItemGroup>
<ContentWithTargetPath Include="..\..\..\Libraries\Core\Business\Vodovoz.Reports\Reports\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>Reports\%(RecursiveDir)\%(Filename)%(Extension)</TargetPath>
</ContentWithTargetPath>
</ItemGroup>

Ignore file from delete during WebDeploy

I'm using TeamCity to build and deploy a collection of MVC Applications via msbuild and WebDeploy.
In a step previous to my solution build/deploy, I copy an app_offline.htm to the deploy directory so that I can perform SQL updates and other web/solution management steps including the build.
One of the setting in the WebDeploy is to delete files that aren't included in the project, or not needed to run the site. This deletes my app_offline.htm file each time. While I understand this is kind of the desired result, is there a way to exclude this file from being deleted from the deployment directory upon the deploy?
I've tried adding an ItemGroup with the ExcludeFromPackageFiles option, with no results.
I had a similar problem, wanting to keep minified javascript files in the deployment package even though they're not part of the project.
I added a custom MSBuild target for this, that works for me:
<!-- ====== Package the minify files ===== -->
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles1;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<PropertyGroup>
<AfterAddIisSettingAndFileContentsToSourceManifest>
MakeEmptyFolders
</AfterAddIisSettingAndFileContentsToSourceManifest>
</PropertyGroup>
<Target Name="CustomCollectFiles1">
<ItemGroup>
<!-- =====Controls\Javascript folder ==== -->
<_CustomFilesForRootFolder Include=".\Controls\Javascript\*.min.js">
<DestinationRelativePath>%(RecursiveDir)%(Filename)%(Extension) </DestinationRelativePath>
</_CustomFilesForRootFolder>
<FilesForPackagingFromProject Include="%(_CustomFilesForRootFolder.Identity)">
<DestinationRelativePath>.\Controls\Javascript\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
This other question " Custom app_offline.htm file during publish " suggests one possible way for the final result you describe:
I use my own
app_offline.htm_
file in the solution, which gets
published. My deployment script then
renames it (removing the trailing _)
to make it active.
I can then run my db scripts/do
whatever then rename the file bringing
the site back.

How to set Visual Studio to Publish pdf files automatically

Is there a way to set visual studio to publish all pdf files?
I know that you can set each individual pdf file in a project with the Build Action
"Content" property.
But that means doing the same thing 100's of times for my current project, is there a way to change a global setting to do the same thing?
there is an easier way, you have to make sure your file is included in the project first, then right-click on the file go to properties, there will be an option "copy to output directory", choose "copy always"
Good luck
Just right click on the file you want to include, choose properties, in the properties window change build action to content. This will include the file during publish.
Add a post build event with the following command:
xcopy "$(ProjectDir)myPdfs\*.pdf" "$(TargetDir)myPdfs\" /S /Y
Note in the above command myPdfs is just a subfolder of your project directory that contains all the PDF files. If you have more than one of these subfolders you need to run the command for each.
Hope this works!!
Suppose you had the PDFs you wish to deploy outside the project in c:\PDFs, modify the .csproj
<ItemGroup>
<Content Include="c:\PDFs\**\*.pdf" />
</ItemGroup>
If they're in a folder "MyPdfs" relative to the root of the project
<ItemGroup>
<Content Include="MyPdfs\**\*.pdf" />
</ItemGroup>
Some further details about this can be found on: https://stackoverflow.com/a/12202917/37055
Open the csproj file and change :
<None Include="my.pdf">
to:
<Content Include="my.pdf">
You could edit your project file directly to add the required <CopyToOutputDirectory>Always</CopyToOutputDirectory> elements to the PDF files. (If your project isn't under source control, test on a copy first and keep backups in case it all goes wrong)
CopyToOutputDirectory will copy the files to the bin folder when you publish. Setting "Build Action" to "Content" will copy the files without the need of CopyToOutputDirectory setting. But this is still needs to be done on each file. You could make a regex replace in project file from <None Include="XXX.pdf" /> to <Content Include="XXX.pdf" />.

Resources