msbuild publish with different app.config - msbuild

I'm currently writing an msbuild script to publish a solution, which is all fine but i want to use a different app.config depending on what configuration is selected.
i've seen people talk about transforms, but this natively only works for web.config (yes you can do it for app.config with a little hacking but doesn't seem to work for the publish task on msbuild)
Creating msbuild script to build, publish with specified app.config, and update from different locations
i've also seen this post but it doesn't actually answer this specific question (After reading the links).
currently my build script looks like:
<PropertyGroup>
<ProjectFile>.\BarcodeScannerApp\BarcodeScannerApp.csproj</ProjectFile>
<SolutionFile>.\BarcodeScannerApp.sln</SolutionFile>
<PublishLoc>http://publishlocation.com</PublishLoc>
<Configuration>release</Configuration>
<GenerateManifests>false</GenerateManifests>
<BootstrapperEnabled>true</BootstrapperEnabled>
<ApplicationVersion>1.0.0.*</ApplicationVersion>
<UpdateEnabled>true</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateUrl>http://backoffice-dev/</UpdateUrl>
</PropertyGroup>
<Target Name="PublishApp">
<MSBuild Projects="$(SolutionFile)"
Targets="Publish"
Properties="PublishUrl=$(PublishLoc);
Configuration=$(Configuration);
GenerateManifests=$(GenerateManifests);
BootstrapperEnabled=$(BootstrapperEnabled);
ApplicationVersion=$(ApplicationVersion);
UpdateEnabled=$(UpdateEnabled);
UpdateMode=$(UpdateMode);
UpdateUrl=$(UpdateUrl)"
/>
</Target>
currently when this script is run, it generates a file BarcodeScannerApp.exe.config which is a copy of the app.config i have in the solution. i want to use a different config file depending on what different configuration i set up (Debug / Release).

As first you need to define properties which references an app.config path for all config files like:
<DebugConfig>...</DebugConfig>
<ReleaseConfig>...</ReleaseConfig>
<TargetConfigPath>...</TargetConfigPath>
And then using WHEN select an appropriate one and rewrite into the target directory
<When Condition="'$(Configuration)'=='DEBUG'">
...
</When>
<When Condition="'$(Configuration)'=='RELEASE'">
...
</When>
You can rewrite files before executing PublishApp targetby introducing new target and create target dependency.

Related

Specify build directory name

I need project to be built into folder:
\bin\Debug 1.0.3.4
Where 1.0.3.4 is a current building assembly version specified in assembly: AssemblyVersion attribute.
I tried using different variables like $(AssemblyVersion), GetAssemblyIdentity task but had no luck.. I'm not so good at using MSBuild.
A quick and dirty solution to this is to, after the build, use GetAssemblyIdentity to extract the version info and then move the $(TargetFile) to the appropriate directory.
This assumes you don't have any dependencies going on. Otherwise, you'll need to modify the $(TargetPath), $(TargetName), and $(TargetExt) or go with the "proper" way of doing it - modifying $(OutputPath) dynamically.
<Target Name="AfterBuild" AfterTargets="Build">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="AssemblyIdentity"/>
</GetAssemblyIdentity>
<PropertyGroup>
<Version>#(AssemblyIdentity->'%(Version)')</Version>
</PropertyGroup>
<Copy SourceFiles="$(TargetPath)" DestinationFolder="$(OutDir)$(Version)" />
</Target>
The proper way would be to modify $(OutDir) aka $(OutputPath), but that would involve things like modifying the AssemblyVersion.cs file (or more complexly, a copy of it injected automatically into the build chain).
You could also instead parse the version from the AssemblyVersion.cs file.

MSBuild Issue while deploying files

I am deploying some files on the server. But when I am doing this, build is deleting all the files and folder which are residing at that location. I don't want to delete all the files from the server. I want to exclude one folder (folder name is Temp) from the destination folder. Temp folder should not get deleted while deleting other files. How to do that?
Here is TFS Build Definition
<PropertyGroup Condition=" '$(DeployEnvironment)' == 'Dev' ">
<DeployPath>\\server1\D$\temp\reports</DeployPath>
</PropertyGroup>
<Target Name="CoreCompileSolution" />
<Target Name="AfterCompile">
<Message Importance ="high" Text="Solution Root: $(SolutionRoot)" />
<Message Importance ="high" Text="Out Dir: $(OutDir)" />
<Copy SourceFiles="#(RPTFiles)" DestinationFolder="$(OutDir)_PublishedWebsites\Reports\" />
</Target>
<Target Name="AfterDropBuild" >
<CreateItem Exclude="$(DeployPath)\Temp*.*">
<Output ItemName="PreviousDeployment" TaskParameter="Include" />
</CreateItem>
</Target>
Why are you using a Copy task? I think it is intended to be used for local manipulations during build, rather than deployment (because it does not give you a chance to easily configure behaviour).
I suggest that instead of copy tsak you use one of the following options
Non-web applications - use Robocopy:
/XD dirs [dirs]... : eXclude Directories matching given names/paths.
XF and XD can be used in combination e.g.
ROBOCOPY c:\source d:\dest /XF *.doc *.xls /XD c:\unwanted /S
see this link for usage guide. You either run it from the command line (using <Exec Command="" > task, or employ MBuiild Community Tasksproject which has a nice wrapper.
Web applications: you should use Web Deploy for your deployments. You an either use MSBuild integration (VS 2010 and later, see this blog series for guidance on setup and configure on VS2010 NB: it has been much simplified in VS 2012, but I don't have a link to share at the moment) or run it from command line (prior to VS 2010):
<Exec Command=""$(WebDeployToolPath)" -verb:sync - source:dirPath='$(MSBuildProjectDirectory)\Published\' -dest:dirPath='$(DeployDirectoryLocalPath)',computerName=$(DeployTargetURL),userName='$(DeployUserName)',password='$(Password)',authType='Basic' -skip:skipaction='Delete',objectname='filePath',absolutepath='app_offline.htm' -skip:skipaction='Delete',objectname='filePath',absolutepath='logs\\.*' -skip:skipaction='Delete',objectname='dirPath',absolutepath='logs\\.*' -skip:skipaction='Delete',objectname='filePath',absolutepath='UserFiles\\.*' -skip:skipaction='Delete',objectname='dirPath',absolutepath='UserFiles\\.*' -verbose -allowUntrusted" />
NB using skip:skipaction='Delete.. to skip removing files and folders.
Update
It looks like I've undestood this a bit incorrect (I supposed, deployment happenned in AfterCompile target, however, as I see now, TFS uses CoreDropBuild target to do the deployment.
So I think, what you need is to override CoreDropBuild target as described: here. (although, I've never tried this).
You can either use Copy task as the author of the thread, or go with Robocopy/webdeploy based on your personal preference.

Adding files to Azure cspkg in afterbuild msbuild event?

I have an MVC application which I have got working on Azure apart from getting the published .cspkg file to include css/jscript that is created in an afterbuild process (this works if I publish to a normal server which isn't using Azure).
In the afterbuild process I minify and merge files then add them to a deploy zip:
<PackageLocation>..\Deploy\Website.zip</PackageLocation>
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
What MSBuild code do I need to change in order to do the same task but adding to the cspkg instead?
Here is how I just did it. In this example I have a .csproj file that is part of an Azure solution and the dll produced by my C# project needs a particular Xml file to live right next to it in the deployment. Here are some msbuild fragments from my .csproj file that show the technique. You can place all of this code below the import of Microsoft.CSharp.targets in your .csproj file.
<!-- Identify the Xml input file that must be deployed next to our dll. -->
<ItemGroup>
<SpecialXmlFileItem Include="c:\temp\MySpecialFile.xml" />
</ItemGroup>
<PropertyGroup>
<!-- In my case I needed the as-deployed Xml filename to be fixed and yet I wanted it to be possible
to provide any filename at all to be provided as the source. Here we are defining the fixed,
as-deployed filename. -->
<AsDeployedXmlFilename>MyServiceStorageConfig.xml</AsDeployedXmlFilename>
<!-- Wire our own AddFilesToProjectDeployment target into the GetCopyToOutputDirectoryItems
target. That target is evaluated not only as part of normal .csproj evaluation, but also as part
of .ccproj evaluation. It is how the .ccproj manages to interrogate your dll producing projects
about all of the project files that need to be packaged. -->
<GetCopyToOutputDirectoryItemsDependsOn>
AddFilesToProjectDeployment;
$(GetCopyToOutputDirectoryItemsDependsOn)
</GetCopyToOutputDirectoryItemsDependsOn>
</PropertyGroup>
<Target Name="AddFilesToProjectDeployment">
<Error Condition="!Exists('#(SpecialXmlFileItem)')"
Text="The all important and very special XML file is not found: %(SpecialXmlFileItem.ItemSpec)" />
<ItemGroup>
<ContentWithTargetPath Include="#(SpecialXmlFileItem->'%(FullPath)')">
<!-- In my case I wanted to deploy my xml file right next to my .dll, so I included no relative
path information in the below value of TargetPath, just the simple filename. But, I think if you
included relative path information in the below value that it would be preserved in the deployment. -->
<TargetPath>$(AsDeployedXmlFilename)</TargetPath>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</ContentWithTargetPath>
</ItemGroup>
</Target>
-Bern McCarty
I think this is just a question of timing... make sure the files get combined, minified, and placed into build before the publishing (packaging) step happens.
Sorry I don't have more details; I've never tried to do this sort of thing.

svc, xml are not being deployed

I'm having problem with publishing WCF service from CI (Cruise Control)..
Let's say I have a WCF project called "WCF-A". I put the following lines in csproj of "WCF-A"
<Target Name="BeforeBuild">
<Message Text="##############Before build##################" Importance="high" />
<RemoveDir Directories="publish" ContinueOnError="true" />
</Target>
<Target Name="AfterBuild">
<Message Text="##############After build##################$(OutputFolder)" Importance="high" />
<MSBuild Projects="$(ProjectName).csproj" Targets="ResolveReferences;_CopyWebApplication" Properties="WebProjectOutputDir=publish\;OutDir=publish\bin\" />
</Target>
I'm using the following to build my service from commandline. (Note that we are using CI but in order to make my question simple, I will use commandline. )
E:\..\Code\>msbuild MyServices.sln /t:Clean;Rebuild
It works perfectly and all assemblies, cross-domain xml, svc files are published under "publish" folder.
The problem come out when I add another services (let's called it "WCF-B") in the solution file. [Edit] I added the same "BeforeBuild" and "AfterBuild" in WCF-B as well. [/Edit] I project-referenced WCF-A from "WCF-B"... but when I build the solution with the same command that I used, the publishing for "WCF-B" is working fine. But the cross-domain file and svc file of "WCF-A" are not being deployed anymore. Only assembly of "WCF-A" are being published under "publish\bin" folder.
Do you guys have any idea why it's happening like that? Thanks in advance.
Edit
I think having "project-reference" creates this problem.. But I need to project-reference instead of calling the service from proxy class. Since both services will be hosted on the same server, I prefer dll-reference over service-calls.
It looks as if the files of WCF-A are being deleted by the BeforeBuild target of WCF-B (assuming that the publish directory resolves to the same directory) and that the assembly WCF-A cannot be deleted because it is referenced by WCF-B and in use.
You might try to increase the log verbosity using /v:d or even /v:diag for further information.
E:\..\Code\>msbuild MyServices.sln /t:Clean;Rebuild /v:d

MSBuild doesn't respect PublishUrl property for my ClickOnce app

I'm trying to make a batch file to publish the few ClickOnce application we have in one click. I'm using msbuild for that, and as an example the below command line shows how I'm doing it:
msbuild
MyApp.sln
/t:Publish
/p:Configuration=Release
/p:PublishUrl="C:\Apps\"
/v:normal > Log.txt
(wrapped for easier reading)
when I run the above command it builds and publish the application in the release directory, i.e. bin\release! Any idea why msbuild doesn't respect PublishUrl property in my example above?
PS: I tried also different combinations including remove 'Configuration', use 'Rebuild' and 'PublishOnly' as targets, and remove the the quotation marks but without any success.
You are setting the wrong property. Try PublishDir instead.
You can pass it into MSBuild as you are or you can set it in the project file (or maybe the sln file too, not sure I always use the project file.) like this
<PropertyGroup>
<PublishDir>C:\Dev\Release\$(BuildEnvironment)\</PublishDir>
</PropertyGroup>
I've just done a few blog posts on MsBuild and ClickOnce stuff, check it out you 'should' find them useful...
Some features are done by Visual-Studio and not by the MSBuild-script. So the click-once-deployment behaves differently when it's executed from the command-line.
The ApplicationRevision isn't increased with every build. This works only when is exectued from Visual Studio
In in somecases, the PublishUrl isn't used. Quote from MSDN:
For example, you could set the PublishURL to an FTP path and set the InstallURL to a Web URL. In this case, the PublishURL is only used in the IDE to transfer the files, but not used in the command-line builds. Finally, you can use UpdateUrl if you want to publish a ClickOnce application that updates itself from a separate location from which it is installed.
I've created a special MSBuild-file which does this things. It runs the publish-target and copies then the files to the right location.
An example of the build-file, as requested by alhambraeidos. It basically runs the regular VisualStudio-build and then copies the click-once data to the real release folder. Note that removed some project-specific stuff, so it's maybe broken. Furthermore it doesn't increase the build-number. Thats done by our Continues-Build-Server:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Publish" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- the folder of the project to build -->
<ProjLocation>..\YourProjectFolder</ProjLocation>
<ProjLocationReleaseDir>$(ProjLocation)\bin\Release</ProjLocationReleaseDir>
<ProjPublishLocation>$(ProjLocationReleaseDir)\app.publish</ProjPublishLocation>
<!-- This is the web-folder, which provides the artefacts for click-once. After this
build the project is actually deployed on the server -->
<DeploymentFolder>D:\server\releases\</DeploymentFolder>
</PropertyGroup>
<Target Name="Publish" DependsOnTargets="Clean">
<Message Text="Publish-Build started for build no $(ApplicationRevision)" />
<MSBuild Projects="$(ProjLocation)/YourProject.csproj" Properties="Configuration=Release" Targets="Publish"/>
<ItemGroup>
<SchoolPlannerSetupFiles Include="$(ProjPublishLocation)\*.*"/>
<SchoolPlannerUpdateFiles Include="$(ProjPublishLocation)\Application Files\**\*.*"/>
</ItemGroup>
<Copy
SourceFiles="#(SchoolPlannerSetupFiles)"
DestinationFolder="$(DeploymentFolder)\"
/>
<Copy
SourceFiles="#(SchoolPlannerUpdateFiles)"
DestinationFolder="$(DeploymentFolder)\Application Files\%(RecursiveDir)"
/>
<CallTarget Targets="RestoreLog"/>
</Target>
<Target Name="Clean">
<Message Text="Clean project:" />
<MSBuild Projects="$(ProjLocation)/YourProject.csproj" Properties="Configuration=Release" Targets="Clean"/>
</Target>
</Project>
I'll put in my 2 cents, this syntax seems to work (right or wrong):
/p:publishUrl="C:\\_\\Projects\\Samples\\artifacts\\Web\\"
For me, the soultion was to escape the path.
Instead of:
/p:PublishUrl="C:\Apps\"
Put:
/p:PublishUrl="C:\\Apps\\"