Copy file using MSBUILD - c#

I am working on a white label xamarin application, and I would like to copy a file from the executing project to the shared .net standard project.
Example
If ClientA.Android project is currently running, I would like to copy a specific file from that project to the .Net Standard project based on if its debug or release config.
I know to copy from a different folder in the same project.
<Target Name="CopyConfigFiles" AfterTargets="Build">
<Copy SourceFiles="$(MSBuildProjectDirectory)/Configuration-Source/$(Configuration)/config.json" DestinationFolder="$(MSBuildProjectDirectory)/Configuration/" />
</Target>
I would appreciate if someone could help me to copy from the executing project rather.

Related

How to reference or copy output of other C# project with a newer framework?

Scenario:
Loader.csproj, which is .NET 4.8; and outputs a .exe with some .dll dependencies
LoaderWrapper.csproj, which is .NET 4.6 and needs to call the .exe of Loader with some arguments.
Main.csproj, which is .NET 4.6 and references LoaderWrapper normally.
I can't create a normal project reference to Loader.csproj from LoaderWrapper.csproj because Loader.csproj is a newer .NET framework.
I can't create an assembly reference as that only copies the .exe file, and not any .dll files the .exe of Loader.csproj depends on.
I can't change the framework version as my application gets loaded in 3d party application Revit, which is .NET 4.6
I can't hardcode the output of Loader.csproj because in my build pipeline I have several different output directories. (eg. for unit tests)
In Visual Studio I can change "Build Dependencies"->"Project Dependencies" on LoaderWrapper.csproj to ensure Loader.csproj gets built, but this doesn't seem to copy/reference the output of Loader.csproj.
So I'm looking for another method to ensure all output of Loader.csproj is included in LoaderWrapper.csproj, and also would end up in Main.csproj through the projectreferences.
Some time ago I solved the similar task - to collect the Content files from one project and include them into the output of another project.
It is not exactly the same task as yours, but you can try to adopt my approach.
So, I has project named MainApp and the project called Lib. The Lib project have the txt file ContentFile.txt with Build Action = Content. I need to include ContentFile.txt into the output of MainApp.
I created CustomBuildActions.targets file in the Lib folder with the following contents
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!--
Define project to get content files from.
Definition relies on the fact that this target file stored
in the same folder with Lib.csproj
-->
<ItemGroup>
<LibProject Include="$(MSBuildThisFileDirectory)/Lib.csproj"/>
</ItemGroup>
<!--
Run msbuild for Lib to collect the list of Content files and store it to the LibContentFiles list.
Then perform string repace to convert paths to Content files to paths inside app bundle. And store results in the LibContentFileTargetPath.
-->
<Target Name="GetBundleFiles" Outputs="#(LibContentFiles)">
<MSBuild Projects="#(LibProject)" Targets="ContentFilesProjectOutputGroup">
<Output ItemName="LibContentFiles" TaskParameter="TargetOutputs"/>
</MSBuild>
<ItemGroup>
<LibContentFileTargetPath Include="#(LibContentFiles->Replace($(MSBuildThisFileDirectory), $(AppBundleDir)/Contents/Resources/))"/>
</ItemGroup>
</Target>
<!-- These targets will fire after mmp creates your bundle but before code signing -->
<PropertyGroup>
<CreateAppBundleDependsOn>$(CreateAppBundleDependsOn);GetBundleFiles;CopyOurFiles;</CreateAppBundleDependsOn>
</PropertyGroup>
<!-- Since this has inputs/outputs, it will fire only when the inputs are changed or the output does not exist -->
<Target Name="CopyOurFiles" Inputs="#(LibContentFiles)" Outputs="#(LibContentFileTargetPath)">
<Message Text="This is us copying a file into resources!" />
<!-- This could have easily been done w/ a built in build action, but you can extend it arbitrary. -->
<Copy SourceFiles="#(LibContentFiles)" DestinationFiles="#(LibContentFileTargetPath)" />
</Target>
</Project>
Then import this target in the MainApp project
<Import Project="../Lib/CustomBuildActions.targets" />
This custom target will collect the Content files from Lib project, transform the paths to preserve folder structure inside MainApp output (e.g. if we will have inside Lib project something like Lib/ContentFolder/Subfolder/contentFile.txt, then inside the bundle if will be placed in Resources/ContentFolder/Subfolder/contentFile.txt) and then copy files inside the bundle.
So, what you can need to adopt:
Use output items of your Loader project instead of content files. So, instead of ContentFilesProjectOutputGroup you will need other target. Please refer to msbuild documentation to find what is best for you.
Change the target dependencies - your custom target should became a dependency of the LoaderWrapper project build steps (in my sample I use CreateAppBundleDependsOn dependency, but it is Xamarin-only thing and you will need to finde the better step to add dependency to).
The full description of my case may be found here https://forums.xamarin.com/discussion/comment/418130

How to publish additional files into bin folder

My .net web app project also includes some unmanaged dlls as additional files.
These are a couple of levels deep in subfolders.
When I publish this project I need these files to be copied to the bin folder alongside all the other binaries.
No matter what settings I try, the best I can get is for them to be published into their existing folder structure which is not where I need them to be.
I've created a PostBuild event to copy the files and this works when building locally but not when publishing to a server. I've not been able to get PostPublish events to work in the same way.
Is there another way to achieve this?
Note this is similar but not the same as a previous question:
Publish unmanaged DLL from referenced project
I have a similar setup. 2 projects in my solution, one .NET Core and the other C++. When I am going to publish the dotnetcoreapp2.2 I want to include the precompiled C++ DLL from the other project.
#JuanR's answer is not working for me, though it is already pretty close to my version. It looks like the <ItemGroup> needs to be in the <Target> tag.
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
<ItemGroup>
<DataModelFiles Include="$(ProjectDir)..\MyCppProject\bin\Release\MyCppProject.dll" />
</ItemGroup>
<Copy SourceFiles="#(DataModelFiles)" DestinationFolder="$(PublishDir)" SkipUnchangedFiles="false" />
</Target>
Try using an after-publish task.
You can create an item group for copy:
<ItemGroup>
<binFilesToCopy Include="$(OutDir)\somepath\to\yourexternalDLLFolder\*" />
<!-- Add more folders/files you want to copy here -->
</ItemGroup>
Then add a target for after publishing:
<Target Name="AfterPublish">
<Copy SourceFiles ="#(binFilesToCopy)" DestinationFolder ="$(OutDir)\bin" />
</Target>
I did this mostly from memory so double-check for syntax, but get you the idea.
In the properties of the file you can set Copy to output directoryto Copy always or you can edit the solution file, expand the xml tag of the file needed and add <CopyToOutputDirectory>Always</CopyToOutputDirectory> as sub-tag.

Change the referenced dll in a SSIS script task at build / deploy or runtime

Recently I have added all of our SSIS projects into a continuous integration pipeline. The projects are built using MSBuild in TeamCity, packaged and pushed to a nuget feed. We deploy them using Octopus and some hand cranked PowerShell built on the back os SQL server management objects (SMO). It all works, with the exception of one project. The project in question contains some script tasks which reference an external assembly. That assembly is built in the same pipeline and its assembly version numbers are updated by part of the process. The problem lies in the fact that the SSIS project now references a strong named dll in the GAC which does not exist because the version numbers have changed.
Does anyone know of a way to either updated the reference at build time on the CI server or override the version number at the point of deployment?
I know this post is quite old but it has been viewed a lot so here's a solution I have found.
You need to include a 'targets' file for the build.
Here's an example Targets file:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<E10BOs>C:\Integrations\E10 Uplifts\Epicor 10.2.600.3</E10BOs>
</PropertyGroup>
<Target Name="BeforeResolveReferences">
<CreateProperty Value="$(E10BOs);$(AssemblySearchPaths)">
<Output TaskParameter="Value" PropertyName="AssemblySearchPaths" />
</CreateProperty>
</Target>
</Project>
The property group E10BOS (and there can be more than 1) then defines the path to the dll's of the version you want to build against.
It needs to be saved as myTargetsFile.targets
Then in a regular VS project you could add this line to the project file (outside of VS in notepad)
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), myTargetsFile.targets))\myTargetsFile.targets" />
</Project>
This uses GetDirectoryNameOfFileAbove to search up the folder tree until it finds you targets file and then imports it. Very useful if you have a lot of different projects all requiring a version change and you don't have to figure out any relative paths!
In SSIS however this doesn't seem to work.
What does is hard-wiring the path to the targets file in the package .dtsx file, again edit it in notepad and add the following line (you will probably see the csharp entry near the end of the project tag as before:
<Import Project="C:\Integrations\E10 Uplifts\Epicor 10.2.600.3\myTargetsFile.targets" />
This will pass through the information of the project references into the scripts.
Then with all of you projects using a targets file changing the version is done by changing the path to the version folder you want them to use.
Hope that helps?

Exclude files from web site deployment with msbuild

I have a web site project that I deploy using msbuild. In the project there are some files and folders that are needed for the build (e.g. the web.config part replacement files) but that I don't want to deploy to the target site.
The best I could think of is a post-build target that removes these files, but I'd like to know if there is a way to have these files not copied to the output folder.
Hi Check this blog post out it saved my day,
I was trying to exclude the un-minified version of the javascripts, and use only the minified version when published (I'm removing large javascripts and chirp.config) its only needed for debug.
just put this on the Project file as stated on the link.
<ItemGroup>
<ExcludeFromPackageFolders Include="Scripts\large">
<FromTarget>Project</FromTarget>
</ExcludeFromPackageFolders>
<ExcludeFromPackageFiles Include="Scripts\mash.js.chirp.config" />
<ExcludeFromPackageFiles Include="Content\mash.js.chirp.config" />
</ItemGroup>
The published site will not include the following:
Scripts\large
mash.js.chirp.config
You can select the files and set their "Build Action" to "ExcludeFromPackageFiles". That way visual studio will edit the csproj xml and you don't have to.
in the properties explorer for the files change the option "copy to output directory to "do not copy"
You can use MSDeploy with Web Publishing Pipeline to exclude files to be included in the package creation.
You can use something like this if you want to exclude for example App_Data folder from the deployed package
<Target Name="ExcludeApp_Data" DependsOnTarget="$(ExcludeApp_DataDependsOn)" Condition="$(ExcludeApp_Data)" >
<ItemGroup>
<ExcludeFromPackageFolders Include="App_Data">
<FromTarget>ExcludeApp_Data</FromTarget>
</ExcludeFromPackageFolders>
</ItemGroup>
</Target>
Somehow editor doesn't display the code properly.
The above gets generated inside the proj file when you configure the Package/Publish web. You can add your own target to get it done.
For example, if you want to exclude Scripts\jquery files from your build, create seperate ExcludeScriptFiles.wpp.targets file as below
<ItemGroup>
<ExcludeFromPackageFolders Include="Internal">
<FromTarget>ExcludeScriptFiles.wpp.targets</FromTarget>
</ExcludeFromPackageFolders>
<ExcludeFromPackageFiles Include="Scripts\jquery.js;xyz.js">
<FromTarget>ExcludeScriptFiles.wpp.targets </FromTarget>
</ExcludeFromPackageFiles>
</ItemGroup>
This is just a simple example to write your own target.
Hope this helps
I'm using Visual Studio 2012 with Jenkins and the only thing that worked for me was changing "Build Action" to "None:"
Internally this sets the XML tag in the PROJECT.csproj file from "Content" to "None:"
<None Include="form.coffee" />
I closed the project then manually edited the file using another editor to exclude all my coffee files en mass.
(All my coffee files are still transcompiled to js files.)

How to use the final {project}.exe.config file when creating a setup project

I have created a console application (blah.exe) with specific app.config's for dev and prod. These are named dev_app.config and prod_app.config. I have hooked up an AfterBuild target in my csproj file* which copies the correct config file to the bin directory as blah.exe.config.
I have also created a setup project for this console app but I have run into a slight issue. It seems that the setup project uses the actual app.config from the project directory as opposed to the final blah.exe.config (located in bin directory).
|--Bin
| |--Debug
| |--Blah.exe.config <--- I want the setup project to use this file
|--app.config <--- Setup project uses this file at the moment
|--dev_app.config
|--prod_app.config
How can I force the setup project to use the final config file generated in the bin folder and not the actual app.config file?
Additional Information:
My current solution involves adding another AfterBuild command which overwrites the actual app.config file. I don't like approach since it forces me to have an additional file that I don't need. Also, having this file has caused me some grief already since I made changes to the app.config file which got overwritten when building. The question is about how to get the setup project use the final config file in the bin folder and NOT how to manage the config or ways to create a config file.
* Adapted from Deploy an app.config based on build configuration
I have been using that exact same scenario but I use the BeforeBuild instead of AfterBuild, and it has always been fine. I have been doing this on both web and windows projects. Below is the code I am using.
<Target Name="BeforeBuild">
<ItemGroup>
<ConfigSourceFiles Include="Web.$(Configuration).config" />
<ConfigDestinationFiles Include="Web.config" />
</ItemGroup>
<Copy SourceFiles="#(ConfigSourceFiles)" DestinationFiles="#(ConfigDestinationFiles)" />
</Target>
Hope this helps.

Categories

Resources