I am Trying to create a Temp folder while doing the publish of my Web Application Project with file system location in Visual Studio 2015.I have tried adding the code below in .csfile but its not Creating folder in the target location of the Publish Directory.If given Static location to create folder its working fine.How can get Publish Directory dynamically?
<Target Name="CustomCollectFiles" AfterTargets="Build">
<MakeDir Directories="$(PublishDirectory)$(OutputDirectoryTemp)" />
</Target>
<PropertyGroup>
<OutputDirectoryTemp>\Temp\</OutputDirectoryTemp>
</PropertyGroup>
Create folder while publishing with MSBuild
You need to declare attributes PublishDirectory by creating an element with the attribute name as a child of the PropertyGroup element, because there is no such MSBuild Macros for this, you can check the Common Macros for Build Commands and Properties.
As test, I set PublishDirectory to the path D:\Publish:
<PropertyGroup>
<PublishDirectory>D:\Publish</PublishDirectory>
</PropertyGroup>
Then I add a output command line <Message Test="xxx" /> in the target to output the content of $(PublishDirectory)$(OutputDirectoryTemp):
<Target Name="CustomCollectFiles" AfterTargets="Build">
<MakeDir Directories="$(PublishDirectory)$(OutputDirectoryTemp)" />
<Message Text="$(PublishDirectory)$(OutputDirectoryTemp)">
</Message>
</Target>
<PropertyGroup>
<OutputDirectoryTemp>\Temp\</OutputDirectoryTemp>
</PropertyGroup>
<PropertyGroup>
<PublishDirectory>D:\Publish</PublishDirectory>
</PropertyGroup>
In the output window, you will see following log:
And the folder Temp would be created:
If you have already defined the variable of PublishDirectory, you can try to use the output command line <Message Test="xxx" /> check if the path is correct.
Update:
I will like to get the target location of the Publish Directory dynamically not static or hard coded
Since you want to get the target location of the Publish Directory dynamically, as we know, the location of the Publish Directory was stored in the .pubxml file, in the node <publishUrl>D:\Publish\Test</publishUrl>, to get this value dynamically, we could use $(publishUrl) to get this value in the target, However, the publishing process is after the build, we could not get this value in the build process, so we need to change the order of this target from AfterTargets="Build" to AfterTargets="PipelineTransformPhase". The target should be:
<Target Name="CustomCollectFiles" AfterTargets="PipelineTransformPhase">
<MakeDir Directories="$(publishUrl)$(OutputDirectoryTemp)" />
<Message Text="$(publishUrl)$(OutputDirectoryTemp)" />
</Target>
<PropertyGroup>
<OutputDirectoryTemp>\Temp\</OutputDirectoryTemp>
</PropertyGroup>
In this case, when you publish your project to the system location, the publish directory will be stored in the publishUrl, we could get it in that target.
Hope this helps.
A little irrelevant at this point in time, but I think it may help someone like me. Whenever I searched how to dynamically add the folders and files within the same project in my publish profile in Azure DevOps, I landed on this question. So, I decided to put my answer here if it can help someone.
MSBuild expects you to make sure that you include certain files into the project file if you want Azure to deploy them during a git deployment. It is very frustrating, especially when you're using an external tool to copy files into a certain folder.
Wouldn’t it be nice if Visual Studio and (therefore) MSBuild just recursively included and deployed a folder of files within the same project without you having to define it in the publish profile?
You have to hand-edit the .csproj/.vbproj file (using Notepad++), but all you need to do is use a wildcard in the Include statement:
MyProject.Web.vbproj
<!-- double wildcards include all files and folders -->
<Content Include="folder\**" />
<!-- You can also filter certain type of files (e.g. .js files) -->
<Content Include="folder\*.min.js" />
It helped me tremendously.
Try specifying your PropertyGroup before your target, to ensure it has been created.
Also check the value of PublishDirectory to make sure it is a valid path - I suspect it may come with a "\" on the end of it, so you're ending up with two slashes
Related
In my .csproj file, I am creating directories containing files, and these directories are being created in the main project directory as intended. For certain reasons, I cannot generate these directories in bin\debug. However, I do not want the files generated in the directories to be included in the project, as I do not want them to be checked in.
How can I exclude the files from my project automatically through msbuild?
For reference, I have tried the following, and though the files get generated as expected, they are still being added to the project unintentionally:
<Target Name="BuildThings" AfterTargets="Build" BeforeTargets="GatherStagingFiles" Inputs="#(Compile)" Outputs="$(GeneratedFilesDirectory)">
<Exec WorkingDirectory="$(MSBuildProjectDirectory)" Command="$(ToolPath) buildpackage -InputDir:$(MSBuildProjectDirectory)\$(OutDir) -OutputDir:$(MSBuildProjectDirectory)\$(GeneratedFilesDirectory)" />
</Target>
<Target Name="HideFiles" DependsOnTargets="BuildThings">
<ItemGroup>
<GeneratedFiles Include="$(MSBuildProjectDirectory)\$(GeneratedFilesDirectory)\file.txt">
<InProject>false</InProject>
</GeneratedFiles>
</ItemGroup>
</Target>
I've added a target section to my csproj file like this.
<Target Name="Spa">
<Exec Command="ng --version" WorkingDirectory="../Spa" />
<Exec Command="ng build --prod" WorkingDirectory="../Spa" />
<Exec Command="del .\wwwroot\* /F /Q /S" />
<Exec Command="copy ..\Spa\dist\Spa\* .\wwwroot" />
</Target>
When I'm executing it using the command below, it does precisely what it's supposed to.
dotnet msbuild /t:Spa
However, it'd be nice if the target could be invoked just prior to the execution of publishing within Visual Studio (b+h+Tab+Enter).
I've read somewhere that it's possible and the docs claim that BeforePublish is the correct target name. However, when I change the name Spa to BeforePublish, I'm not getting the effect of my SPA being built and copied over.
What am I missing and how do I automate the process?
How to run MsBuild with specific target when publishing?
I post an answer here to make sure this question more clear.
For this question, The first thing to note is that it is related to the project type. If you are publish a WPF/Winodws Forms project, the <Target Name="BeforePublish "> should be works as expected. That because these project types include the target publish by default, so the target "BeforePublish" will work as expected.
However, the web project not contain this default target Publish, so if you use <Target Name="BeforePublish "> in the web project, it will not executed as expected. To resolve this issue, we could add a BeforeTargets="BeforePublish" to the target, like:
<Target Name="Spa" BeforeTargets="BeforePublish">
...
</Target>
Then Overriding "DependsOn" Properties:
<PropertyGroup>
<BuildDependsOn>
BeforeBuild;
CoreBuild;
AfterBuild;
BeforePublish
</BuildDependsOn>
</PropertyGroup>
Or you can simple add AfterTargets="Build" to the target Spa, it should woks fine:
<Target Name="Spa" AfterTargets="Build">
...
</Target>
The second thing to note is that whether the target section needs to be at the bottom of the csproj file is depends on the style csproj. Just as Martin said, if you are in the old style csproj, those targets BeforeBuild, AfterBuild are actually pre-defined in the Microsoft.Common.targets file that contains the Visual Studio Build process, so we have to set our custom target at the bottom of the csproj to overwrite it in the Microsoft.Common.targets file. If you are in the new style csproj(), it doesn't matter where you set it.
Hope this helps.
I'm busy moving my code from .Net Framework libraries to .netstandard2.0 libraries. So far it's going pretty well, but now i'm stuck with the in the .csproj file.
The existing project file has this defined
<Target Name="Rebuild">
<Exec Command="echo Now Rebuilding the package" />
</Target>
the actual command executes an exe that generates a bunch of xml classes based on an xsd.
I cannot get this to work in a .netstandard2.0 project?
I've searched everywhere but i cannot find a reason for this not working...
I suspect that in your specific instance, the Rebuild target will be overwritten by the sdk targets that are implicitly imported after your code. If you want to overwrite SDK-provided tasks, you need to change to explicit SDK imports (instead of <Project Sdk="...">):
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<!-- other project content -->
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<Target Name="Build">
<!-- overwrite Build target here -->
</Target>
<Target Name="Rebuild">
<!-- overwrite Rebuild target here -->
</Target>
</Project>
The Exec target is supported though the echo command may or may not work depending on the platform you are running it on (since echo may be just a built-in command of the shell but no executable that can be run).
Make sure that:
The command starts with the path to an executable that is found on the PATH or is specified absolute or relative to the csproj file being built.
The target is actually executed. E.g. some programs could use /t:Clean;Build instead of /t:Rebuild.
How can I merge and make use of Web.debug.config in visual studio 2010 built-in debugger?
This is a known bug. That feature can be used right now only as part of the deploy process.
https://connect.microsoft.com/VisualStudio/feedback/details/523221/have-web-debug-config-apply-during-development
Please upvote it, if you encounter this too, so this will be fixed ASAP.
This is actually quite simple to do and, believe it or not, it seems this is the way VS is designed to work.
Add the following lines verbatim right before the closing "Project" tag of the .csproj file of the project that contains web.config.
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="Transform">
<MakeDir Directories="obj\$(Configuration)" Condition="!Exists('obj\$(Configuration)')" />
<TransformXml Source="Web.Config" Transform="Web.$(Configuration).config" Destination="obj\$(Configuration)\Web.config" StackTrace="true" />
</Target>
Put the following lines verbatim to the post-build event in the project properties of the project that contains the web.config file. Do this for each build configuration you want the transformations to run for.
"$(MSBUILDBINPATH)\msbuild" "$(ProjectPath)" /t:Transform /p:Configuration=$(ConfigurationName);Platform=AnyCPU
xcopy "$(ProjectDir)obj\$(ConfigurationName)\Web.Config" "$(ProjectDir)". /F /R /Y
I had solved this in a simpler way, by adding this at the end of the .csproj file, right before the tag. This is similar to keitn's answer, with the difference that it doesn't use a post build event.
<Target Name="BeforeBuild">
<TransformXml Source="Web.config" Transform="Web.$(Configuration).config" Destination="Web.config" />
</Target>
I didn't want to update the web.config in my project just the one that ends up in the bin folder so here is how I did it.
Add the following to the end of .csproj (just before the final closing project tag)
<Target Name="Transform">
<MakeDir Directories="bin" Condition="!Exists('bin')" />
<TransformXml Source="Web.Config" Transform="Web.$(Configuration).config" Destination="bin\$(TargetFileName).config" StackTrace="true" />
</Target>
Then add the following post build step
"$(MSBUILDBINPATH)\msbuild" "$(ProjectPath)" /t:Transform /p:Configuration=$(ConfigurationName);Platform=AnyCPU
This means that when you build a transform takes place from the debug/release config to WebsiteName.Config file in the output bin directory thus not interfering with the main web.config in the project.
After reading many similar posts and having problems with files not being able to be overwritten or web.config not being accessible because it is read only this is what I got working for me:
<Target Name="BeforeBuild" Condition="$(Configuration) == 'MyAltDebugConfiguration'">
<ItemGroup>
<OriginalWebConfig Include="$(ProjectDir)Web.config"/>
<TempWebConfig Include="$(ProjectDir)TempWeb.config"/>
</ItemGroup>
<Exec Command=""$(DevEnvDir)tf.exe" checkout "$(ProjectDir)Web.config"" />
<Copy SourceFiles="#(OriginalWebConfig)" DestinationFiles="#(TempWebConfig)" />
<TransformXml Source="$(ProjectDir)TempWeb.config"
Transform="Web.$(Configuration).config"
Destination="Web.config" />
</Target>
Notes:
This runs as the BeforeBuild target.
I only want it to run under a certain configuration (an alternative debug environment) and so that is why I have the Condition. When deploying via web deploy the publishing target kicks in and I don't need this target to run.
I don't want to have to remember to check out web.config (only to undo it when I am done) so I check web.config out before beginning the transform. If you aren't using TFS you can remove this line.
Because VS (2010) \ msbuild doesn't want to let go of the Source web.config I use a temp file (thanks to this article for the info: http://www.diaryofaninja.com/blog/2011/09/14/using-custom-webconfig-transformations-in-msbuild)
I tried adding a command to delete the TempWeb.config but VS \ msbuild doesn't want to let go of it. I can live with it as it doesn't get added to TFS.
I know this is old, but I'm facing the same problem. We have Test, Staging, Live configs that replace endpoints, connection strings etc. from the default Web.config
However I would do the following:
Right click on the desired transform config (e.g. Web.Live.config)
Click on "Preview Transform"
Copy everything from right (it's how the Web.config looks with the transformation)
CTRL+A + CTRL+C
Open Web.config file (default one)
Select everything (CTRL+A) and paste it in (CTRL+V)
Run
It's not that many steps and is done pretty quickly when you get a hang of it. Hope this helps. :)
#ologesa:
Your solution needs write access to the original Web.config (you must check-out in TFS).
The better solution is to directly generate the Web.config in the bin folder like keitn does this. When we combine keitn's and your solution we get this one:
<Target Name="BeforeBuild">
<Message Text="Transforming Web.config from Web.$(Configuration).config" Importance="high" />
<MakeDir Directories="bin" Condition="!Exists('bin')" />
<TransformXml Source="Web.Config" Transform="Web.$(Configuration).config" Destination="bin\$(TargetFileName).config" StackTrace="true" />
</Target>
I'm thinking that the final result is going to be "it can't be that easily done", but just seems like it should be. I have a personal project I am working on. I'd hate to have to manually (or even in script) change versions, company, copyright, and all that on ALL the assembly.cs files and would like all that to be either in a script or in a file I can change (so the script stays the same mostly) when I want to update the version. But it seems like MSBuild is mostly a "build as is specified in Visual Studio". I'd just hate to have all that history of these files where I change just the version and possibly even make a mistake as this project will continue to get bigger and bigger. I'd like to just be able to add a new project to Visual studio and have whatever command line in my powershell script just say "compile this, but give it this company name and this file version instead of whatever is listed in the code file".
Google has NOT proven fruitful in this. I've even found it difficult to build my files to a specific folder. I've had to so far make sure all my projects are 2 folders deep and was able to say to build them at ....\, but I would like to be able to change that randomly if I like and have them built elsewhere if I so desire.
Is MSBuild perhaps not the way to go? Is there someway else to build visual studio that would be better from command line? Eventually I also want to auto build the install with wix and be able to match its version with the binary versions.
thank you
Since csproj is xml, you can use XmlUpdate "helpers" to modify the values inside the csproj file before you do your build.
For other files, you can use some other Tasks to do the job.
Here is one helpful target:
http://msbuildtasks.tigris.org/ and/or https://github.com/loresoft/msbuildtasks has the ( FileUpdate (and SvnVersion task if that is your Source-Control) ) tasks.
<Target Name="BeforeBuild_VersionTagIt_Target">
<ItemGroup>
<AssemblyInfoFiles Include="$(ProjectDir)\**\*AssemblyInfo.cs" />
</ItemGroup>
<!--
<SvnVersion LocalPath="$(MSBuildProjectDirectory)" ToolPath="$(SVNToolPath)">
<Output TaskParameter="Revision" PropertyName="MyRevision" />
</SvnVersion>
-->
<PropertyGroup>
<MyRevision>9999</MyRevision>
</PropertyGroup>
<FileUpdate Files="#(AssemblyInfoFiles)"
Regex="AssemblyFileVersion\("(\d+)\.(\d+)\.(\d+)\.(\d+)"
ReplacementText="AssemblyFileVersion("$1.$2.$3.$(MyRevision)" />
</Target>
Below is an example of manipulating the csproj(xml).
How to add a linked file to a csproj file with MSBuild. (3.5 Framework)
But basically, when you build, you can put all the repetative stuff in a msbuild definition file (usually with the extension .proj or .msbuild)...and call msbuild.exe MyFile.proj.
Inside the .proj file, you will reference your .sln file.
For example:
$(WorkingCheckout) would be a variable (not defined here)...that has the directory where you got a copy of hte code from your source-control.
<Target Name="BuildIt" >
<MSBuild Projects="$(WorkingCheckout)\MySolution.sln" Targets="Build" Properties="Configuration=$(Configuration)">
<Output TaskParameter="TargetOutputs" ItemName="TargetOutputsItemName"></Output>
</MSBuild>
<Message Text="BuildItUp completed" />
</Target>
So below is the more complete example.
You would save this as "MyBuild.proj" and then call
"msbuild.exe" "MyBuild.proj".
Start .proj code. (Note, I did not import the libraries for the FileUpdate Task)
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="AllTargetsWrapped">
<PropertyGroup>
<!-- Always declare some kind of "base directory" and then work off of that in the majority of cases -->
<WorkingCheckout>.</WorkingCheckout>
</PropertyGroup>
<Target Name="AllTargetsWrapped">
<CallTarget Targets="BeforeBuild_VersionTagIt_Target" />
<CallTarget Targets="BuildItUp" />
</Target>
<Target Name="BuildItUp" >
<MSBuild Projects="$(WorkingCheckout)\MySolution.sln" Targets="Build" Properties="Configuration=$(Configuration)">
<Output TaskParameter="TargetOutputs" ItemName="TargetOutputsItemName"></Output>
</MSBuild>
<Message Text="BuildItUp completed" />
</Target>
<Target Name="BeforeBuild_VersionTagIt_Target">
<ItemGroup>
<AssemblyInfoFiles Include="$(ProjectDir)\**\*AssemblyInfo.cs" />
</ItemGroup>
<!--
<SvnVersion LocalPath="$(MSBuildProjectDirectory)" ToolPath="$(SVNToolPath)">
<Output TaskParameter="Revision" PropertyName="MyRevision" />
</SvnVersion>
-->
<PropertyGroup>
<MyRevision>9999</MyRevision>
</PropertyGroup>
<FileUpdate Files="#(AssemblyInfoFiles)"
Regex="AssemblyFileVersion\("(\d+)\.(\d+)\.(\d+)\.(\d+)"
ReplacementText="AssemblyFileVersion("$1.$2.$3.$(MyRevision)" />
</Target>
</Project>
To enhance the above, you would create a new target that would run before "BeforeBuild_VersionTagIt_Target", that would pull your code from source-control and put it in the $(WorkingCheckout) folder.
The basic steps would then be: 1. Checkout code from Source-Control. 2. Run the targets that alter the AssemblyVersion (and whatever else you want to manipulate) and 3. Build the .sln file.
That's the basics of a .proj file. You can do much more. Usually by using helper libraries that already exists.