Specifying assembly version of all projects within a web deployment wdproj script - msbuild

I have a .wdproj Web Deployment Project created with VS2010 that contains references to other class libraries, like this:
<Project ToolsVersion="4.0" DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ProjectReference Include="..\Path\Proj1.csproj">
<Project>{GUID-HERE}</Project>
<Name>Proj1</Name>
</ProjectReference>
<ProjectReference Include="..\Path\Proj2.csproj">
<Project>{GUID-HERE}</Project>
<Name>Proj2</Name>
</ProjectReference>
There are lots of these. I want to be able to run msbuild /t:Rebuild /p:Configuration=Release and have all the assemblies of all the included projects compiled at a specified version. Nothing fancy just static like 2.5.6.0 and specified once in the wdproj file. I dont want to open 30 files manually.
I have looked at MSBuild Community Task and MSBuildExtension Pack and can not get anything to work. The build runs ok without errors.
Anyone have an example of how this can be done?
This is an attempt with MSBuild Extensions (adapted from the sample included) that doesn't work:
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.VersionNumber.targets"/>
<Target Name="Build">
<MSBuild.ExtensionPack.Framework.AssemblyInfo
ComVisible="true"
AssemblyInfoFiles="VersionInfo.cs"
AssemblyFileMajorVersion="2"
AssemblyFileMinorVersion="5"
AssemblyFileBuildNumber="6"
AssemblyFileRevision="0"
/>
</Target>
MSBuild is definately looking at the MSBuild.ExtensionPack.Framework.AssemblyInfo element because if the attribute names are incorrect the build will fail. This builds ok but none of the versions on the referenced assemblies are changed. The version numbers on the ASP.NET page assemblies from the website are all 0.0.0.0.

Are you maybe missing to specify the CodeLanguage and OutputFile attributes?
I think the AssemblyInfo task is intended to generate (replace) a source file prior to compiling.

Related

MSBuild: How may I access built-in properties while defining my own custom properties?

I have a file named Common.targets defined like so:
<Project>
<PropertyGroup>
<TlbExpPath>"c:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\x64\tlbexp"</TlbExpPath>
<TlbOutPath>"$(OutDir)..\TLB\$(TargetName).tlb"</TlbOutPath>
</PropertyGroup>
<Target Name="TlbExp" AfterTargets="CopyFilesToOutputDirectory" Inputs="$(TargetPath)" Outputs="$(TlbOutPath)">
<Exec Command='$(TlbExpPath) "$(TargetPath)" /nologo /win64 /out:$(TlbOutPath) /verbose' />
</Target>
</Project>
When I inspect the output of the TlbOutPath property, it looks like:
"..\TLB\.tlb"
Apparently, $(OutDir) and $(TargetName) produce nothing when used within a PropertyGroup. I'm not sure why. How can I make these paths/values reusable while still having access to built-in properties when they are defined?
I'm using MSBuild that comes bundled with Visual Studio 2019. I add an Import element to my actual .csproj projects to include this target where I need it. The csproj projects use the SDK format for the projects, e.g. <Project Sdk="Microsoft.NET.Sdk">.
Here is an example of what the import looks like:
<Project Sdk="Microsoft.NET.Sdk">
<!-- etc -->
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<!-- etc -->
</ItemGroup>
<Import Project="$(RepositoryRoot)\Common.targets" />
</Project>
MSBuild: How may I access built-in properties while defining my own
custom properties?
This is quite an issue in the new sdk format project. I have tested it and got the same issue as you said which quite bother me a lot. Like $(OutDir),$(TargetName),$(OutputPath),$(TargetPath) and some other common system properties cannot be used in a new property while $(Configuration) and $(AssemblyName) works well.
And not only us but also someone else also face the same issue about it.See this thread.
For the traditional old csproj format project, there was no problem with these properties being used this way, but in the new SDK format project, it is impossible to assign some common properties such as $(OutDir),$(TargetName) and $(TargetPath) to a new property. As we know, most of the common properties are defined in the Microsoft.Common.props file(old csproj format) which is quite different from the new sdk format project which does not have such file.
In order to get an answer,l have reported this issue to DC Forum. See this.You can enter this link and add any detailed comments to describe this issue. And anyone who interested in this issue will also vote it so that it will get more Microsoft staff's attention. All these efforts will speed up and get the final answer.
This process may take a while or you could try my suggestion.
Suggestion
1) You can customize this property $(OutDir) in Common.targets file, and use $(TargetFramework) instead of $(TargetName) since $(TargetFramework) is defined in the xxxx.csproj file.
<Project>
<PropertyGroup>
<OutDir>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName)\</OutDir>
<TlbExpPath>"c:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\x64\tlbexp"</TlbExpPath>
<TlbOutPath>"$(OutDir)..\TLB\$(TargetName).tlb"</TlbOutPath>
<TargetPath>xxxx\xxxx.dll(exe)</TargetPath>--------the absolute path of the output file
</PropertyGroup>
<Target Name="TlbExp" AfterTargets="CopyFilesToOutputDirectory" Inputs="$(TargetPath)" Outputs="$(TlbOutPath)">
<Exec Command='$(TlbExpPath) "$(TargetPath)" /nologo /win64 /out:$(TlbOutPath) /verbose' />
</Target>
</Project>
2) use Directory.Build.targets file rather than a custom targets file.
A) You should add a file named Directory.Build.targets(it must be named this and have its own rule to be imported into xxx.csproj) under the project folder.
B) add the content of Common.targets into it without any changes and then build your project directly. The Directory.Build.targets will be imported into your project automatically while build.
This function works well and will not lose any properties. However, l stil bother why it works.
Conclusion
I think #2 is more suitable and easier for you to achieve your goal.

MSBuild multiple dll in a single NuGet package

I have a Visual Studio 2017 solution that contains two projects:
Foo.csproj
Foo.Core.csproj
Both of these projects target multiple frameworks: net452;netstandard1.2
Foo.csproj includes a project reference to Foo.Core.csproj:
<ItemGroup>
<ProjectReference Include="..\Foo.Core\Foo.Core.csproj" />
</ItemGroup>
When I generate a NuGet package for Foo.csproj, I want the nupkg file to include both of these assemblies.
What is currently happening is that the NuGet package that gets created has Foo.dll and then a NuGet dependency on Foo.Core (which doesn't exist).
How can I generate a single NuGet package using msbuild that will include both assemblies?
For reference this is the command I am currently using (which is not working how I want it to):
msbuild /p:restore,pack Foo.csproj
This is currently not directly supported by NuGet out of the box. You can follow this GitHub issue for updates.
However, there are a few ways to create such NuGet package.
Use the "Nugetizer 3000"
This is an newly developed tool to build NuGet packages from projects and works by installing the NuGet.Build.Packaging nuget package. You can find some documentation on it on its GitHub wiki page but since it is a very new project, there isn't much documentation or community knowledge around it yet(!) (but the team developing it is very helpful, you could file GitHub issues if you get stuck).
Adding a custom target in the project (2.0.0 tooling / VS 2017 15.3+): Create an item in the csproj that will include the referenced project's output DLL
This approach is very hacky as it relies on an internal MSBuild item that the pack targets use. It works by first marking the <ProjectReference> to not be referenced from the created nuget package like this:
<ProjectReference Include="..\libA\libA.csproj" PrivateAssets="All"/>
Then you can add this to the project to include the generated libA.dll in the nuget package:
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludeP2PAssets</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="IncludeP2PAssets">
<ItemGroup>
<BuildOutputInPackage Include="$(OutputPath)\testprivatelib.dll" />
</ItemGroup>
</Target>
Note that this requires you to add all the <PackageReference> items of the referenced project to the project you generate the package from since they would be missing from the generated package since you effectively disabled the transitive reference behaviour.
Create a custom .nuspec file
At the time of writing, this is probably the most "supported" way, but also the most complex. NuGet allows you to disable the automatic generation of the resulting .nuspec file and automatic collection of files by setting the <NuspecFile> property in your project, along with a <NuspecProperties> property that allows you to pass replacement tokens for parsing the .nuspec file.
This works by modifying the project file like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<NuspecFile>$(MSBuildThisFileDirectory)$(MSBuildProjectName).nuspec</NuspecFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\LibB\LibB.csproj" />
</ItemGroup>
<Target Name="SetNuspecProperties" BeforeTargets="GenerateNuspec">
<PropertyGroup>
<NuspecProperties>$(NuspecProperties);id=$(AssemblyName)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);config=$(Configuration)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);version=$(PackageVersion)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);description=$(Description)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);authors=$(Authors)</NuspecProperties>
</PropertyGroup>
</Target>
</Project>
This will automatically look for a .nuspec file with the same name as the project (somelib.csproj => somelib.nuspec) and pass some properties along to it. The properties are created in a target in order to be able to access fully resolved and defaulted properties like PackageVersion.
The .nuspec file could look like this:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>$id$</id>
<version>$version$</version>
<authors>$authors$</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description$</description>
<dependencies>
<group targetFramework=".NETStandard1.4">
<dependency id="NETStandard.Library" version="1.6.1" exclude="Build,Analyzers" />
</group>
</dependencies>
</metadata>
<files>
<file src="bin\$config$\netstandard1.4\*.dll" target="lib\netstandard1.4\" />
</files>
</package>
Note that you must add all referenced NuGet packages as a <dependency> element in the .nuspec file since these are no longer automatically generated from the <PackageReference> items in your project file. Refer to the NuSpec Reference for more details.
I have recently created an example project on GitHub demonstrating the use of a custom .nuspec file for exactly this purpose.
The second option that Martin Ullrich mentioned is the only one that works out of the box with .NET Standard that allows to "Generate NuGet package on build" as an integral part of the build.
However like he mentions it has a "hard coded" dependency on a dll with an exact name that you expect to be there (on the output folder) which might bite you in the future. I've found a better alternative which worked for me in .NET Standard without the need of any other modification on this post.
I'll quote it here for completeness.
First you edit your csproj and define the PrivateAssets tag for the reference that you'd like to include:
<ItemGroup>
<ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
Then you add this to your csproj:
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="#(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'all'))" />
</ItemGroup>
</Target>
That post also shows how to include the PDBs in the NuGet package option if necessary (which I omitted here).
Been struggling with the same issue and none of the suggested workarounds worked (https://github.com/NuGet/Home/issues/3891) and I couldn't change the csproj to use the new SDK coming with .netcore.
Luckily the nuget pack command comes with the -IncludeReferencedProjects option (ref: https://learn.microsoft.com/en-us/nuget/tools/cli-ref-pack) which does exactly that:
"Indicates that the built package should include referenced projects either as dependencies or as part of the package. If a referenced project has a corresponding .nuspec file that has the same name as the project, then that referenced project is added as a dependency. Otherwise, the referenced project is added as part of the package."
Regardless of the *.nuspec file (not needed here) , add -IncludeReferencedProjects to the pack command and the referenced project dlls will be included along with the nuget dll.
nuget.exe pack yourProject.csproj -IncludeReferencedProjects
I have recently discovered that you CANNOT set defaults for the Nuspec Properties you want to replace in the msbuild command line e.g. if a metadata value is set in the .csproj file of "<Version>2.0.0</Version>" and you run:
msbuild myproject.csproj -t:pack -p:Configuration=Release -p:NuspecProperties=Configuration=Release;PackageVersion=1.2.3
Your .nupgk file will have the version 2.0.0 still. Annoyingly the MS documentation is not clear on this and no error is displayed.

MSBuild: Ignore targets that don't exist

Solution1.sln contains two projects:
ProjectA.csproj
ProjectB.csproj
ProjectB has a custom target called "Foo". I want to run:
msbuild Solution1.sln /t:Foo
This will fail because ProjectA doesn't define the "Foo" target.
Is there a way to make the solution ignore the missing target? (E.g., do nothing if the target doesn't exist for a specific project) without modifying the SLN or project files?
There is a two-part solution if you don't want to edit the solution or project files and you're happy for it to work from MSBuild command-line but not from Visual Studio.
Firstly, the error you get when you run:
MSBuild Solution1.sln /t:Foo
Is not that ProjectA does not contain a Foo target but that the solution itself does not contain a Foo target. As #Jaykul suggests, setting the MSBuildEmitSolution environment variable will reveal the default targets contained within the solution metaproj.
Using the metaproj as inspiration you can introduce a new file "before.Solution1.sln.targets" next to the solution file (the file name pattern is important) with contents like this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Foo">
<MSBuild Projects="#(ProjectReference)" Targets="Foo" BuildInParallel="True" Properties="CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" SkipNonexistentProjects="%(ProjectReference.SkipNonexistentProjects)" />
</Target>
</Project>
The MSBuild element is mostly just copied from the solution metaproj's Publish target. Adjust the target name and any other details to suit your scenario.
With this file in place, you'll now get the error that ProjectA does not contain the Foo target. ProjectB may or may not build anyway depending on inter-project dependencies.
So, secondly, to solve this problem we need to give every project an empty Foo target which is then overridden in projects that actually already contain one.
We do this by introducing another file, eg "EmptyFoo.targets" (name not important) that looks like this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Foo" />
</Project>
And then we get every project to automatically import this targets file either by running MSBuild with an extra property, eg:
MSBuild Solution1.sln /t:Foo /p:CustomBeforeMicrosoftCommonTargets=c:\full_path_to\EmptyFoo.targets
Or include the CustomerBeforeMicrosoftCommonTargets property in the Properties attribute on the MSBuild element in the first targets file where you could optionally specify the full path relative to the $(SolutionDir) property.
However, if you're willing to run Foo in conjunction with any of the default solution targets (ie Build, Rebuild, Clean, or Publish) you could take some inspiration for how the Web Publishing Pipeline in MSBuild uses the DeployOnBuild property to call the Publish target on Web projects in a solution containing other project types that don't support publishing.
More info on the before.Solution1.sln.targets file here:
http://sedodream.com/2010/10/22/MSBuildExtendingTheSolutionBuild.aspx
You can target those by project name, like /t:project:target (might need quotes, I can't remember).
You can find all the generated targets by setting the environment variable MSBuildEmitSolution = 1 ... which causes msbuild to save to disk the temp .metaproj file which it generates for your solution. That file has all those targets defined in it, just open it up and take a look ;)
Maybe not the best answer but a reasonable hack.
msbuild ProjectA.csproj
msbuild ProjectB.csproj /t:Foo
When msbuild building solution - msbuild emits only limited set of targets into it's .metaproj file, and afaik - you can't build custom target through building sln file, you have to use original project1.csproj or custom build script.
Just for reference:
Use ContinueOnError when using MSBuildTask or -p:ContinueOnError=ErrorAndContinue when using (dotnet) msbuild
It may be in limited scenarios helpful: For example you have a list of .csproj files and want attach metadata only to specific project file items then you could write something like this:
<Target Name="UniqueTargetName" Condition="'$(PackAsExecutable)' == 'Package' Or '$(PackAsExecutable)' == 'Publish'" Outputs="#(_Hello)">
<ItemGroup>
<_Hello Include="$(MSBuildProjectFullPath)" />
</ItemGroup>
</Target>
<Target Name="BuildEachTargetFramework" DependsOnTargets="_GetTargetFrameworksOutput;AssignProjectConfiguration;_SplitProjectReferencesByFileExistence"
Condition="$(ExecutableProjectFullPath) != ''">
<Message Text="[$(MSBuildThisFilename)] Target BuildEachTargetFramework %(_MSBuildProjectReferenceExistent.Identity)" Importance="high" />
<MSBuild
Projects="%(ProjectReferenceWithConfiguration.Identity)"
Targets="UniqueTargetName"
ContinueOnError="true">
<Output TaskParameter="TargetOutputs" ItemName="_Hallo2" />
</MSBuild>
<Message Text="[$(MSBuildThisFilename)] ########### HELLO %(_Hallo2.Identity)" Importance="high" />
</Target>

How to change Assembly Version Number using AssemblyInfoTask?

I am trying to automate the process for setting the Version for all DLL's, after spending some time I came to know the AssemblyInfo Task with which it can most likely be achieved.
So I went ahead and installed it, specifically version 1.0.51130.0.
After Installing, I manually added the Import Tag (by unloading the each project) of AssemblyInfoTask in .cspoj files (the solution has more than 35 proj files).
<Import Project="$(MSBuildExtensionsPath)\Microsoft\AssemblyInfoTask\Microsoft.VersionNumber.Targets"/>
Next I modified the Microsoft.VersionNUmber.Target file which will be installed in path: C:\Program Files\MSBuild\Microsoft\AssemblyInfoTask, and I modified the following section:
<!-- Properties for controlling the Assembly Version -->
<PropertyGroup>
<AssemblyMajorVersion>4</AssemblyMajorVersion>
<AssemblyMinorVersion>0</AssemblyMinorVersion>
<AssemblyBuildNumber></AssemblyBuildNumber>
<AssemblyRevision></AssemblyRevision>
<AssemblyBuildNumberType>DateString</AssemblyBuildNumberType>
<AssemblyBuildNumberFormat>01MMdd</AssemblyBuildNumberFormat>
<AssemblyRevisionType>AutoIncrement</AssemblyRevisionType>
<AssemblyRevisionFormat>00</AssemblyRevisionFormat>
</PropertyGroup>
<!-- Properties for controlling the Assembly File Version -->
<PropertyGroup>
<AssemblyFileMajorVersion>4</AssemblyFileMajorVersion>
<AssemblyFileMinorVersion>0</AssemblyFileMinorVersion>
<AssemblyFileBuildNumber></AssemblyFileBuildNumber>
<AssemblyFileRevision></AssemblyFileRevision>
<AssemblyFileBuildNumberType>DateString</AssemblyFileBuildNumberType>
<AssemblyFileBuildNumberFormat>01MMdd</AssemblyFileBuildNumberFormat>
<AssemblyFileRevisionType>AutoIncrement</AssemblyFileRevisionType>
<AssemblyFileRevisionFormat>00</AssemblyFileRevisionFormat>
</PropertyGroup>
Next I set the assemblyInfo.cs file's version to 1.0.0.0 in every project. Finally I saved and close it, reopened solution, and built. It works like a champ!
Now what want is to customize the Version to 4.0.1053.1 where 10 is the part of year indicator which is 2010 and 53 denotes the week number, at last 1 denotes revision number.
How to achieve this using the AssemblyInfo Task? I came across several posts that a new version of AssemblyInfo Task is available in Build Extension Pack.
I have installed the MSBuild Extension Pack December 2010 and its version is MSBuild Extension Pack 4.0.2.0 Installer
First.. use a globalassemblyinfo.cs that is linked from each project.
Add its as linked file to each project.
This means you update one file, not 30+ assemblyinfo files...then:
use MSBuild.Community.Tasks....
Then call
<AssemblyInfo CodeLanguage="CS"
OutputFile="$(VersionFile)"
AssemblyCompany="Company"
AssemblyProduct="Product"
AssemblyCopyright="Copyright © Company 2011"
ComVisible="false"
AssemblyVersion="$(BUILD_NUMBER)"
AssemblyFileVersion="$(BUILD_NUMBER)" />
Assuming you have something like:
<Import Project=".\tasks\MSBuild.Community.Tasks.Targets"/>
I do this in Jenkins by having a package build that is parameterised using the List Subversion Tags parameter type. The Subversion tag must follow the version number format (major.minor.revision.build), e.g. tags/2.0.0.1. The tag name is then assigned to a Jenkins parameter, e.g. $VERSION becomes 2.0.0.1
I use the WriteLinesToFile msbuild task to write out the assembly attribute to a second file alongside the PropertyInfo.cs called VersionInfo.cs. As checked in to source control, this just contains a default version number:
// Do not change this. The version is set on package builds only by setting the AsmVersion MSBuild property
[assembly: System.Reflection.AssemblyVersion("0.0.0.0")]
The package build on the build server passes in the version via the AsmVersion parameter:
/p:AsmVersion=$VERSION
The .csproj file is modified to have a BeforeBuild target (Visual Studio creates a commented out one for you):
<Target Name="BeforeBuild">
<WriteLinesToFile
Condition=" '$(AsmVersion)' != '' " File="Properties\VersionInfo.cs"
Overwrite="True"
Lines="[assembly: System.Reflection.AssemblyVersion("$(AsmVersion)")] // Generated by build" />
</Target>
When building in Visual Studio, or without passing in the AsmVersion, your assembly will have a default version of 0.0.0.0. When building in the package build, you will get your desired build number.
As #bruceboughton proposed, you can easily generate a version assembly file during compilation without using MSBuild.Community.Tasks library:
<PropertyGroup>
<Version>0.0.0</Version>
<InformationalVersion>0.0.0-dev~commithash</InformationalVersion>
<VersionFileName>$(BaseIntermediateOutputPath)Version.cs</VersionFileName>
</PropertyGroup>
<Target Name="GenerateVersionFile" BeforeTargets="BeforeBuild">
<WriteLinesToFile
File="$(VersionFileName)"
Overwrite="True"
Lines="
[assembly: System.Reflection.AssemblyVersion("$(Version)")]
[assembly: System.Reflection.AssemblyFileVersion("$(Version)")]
[assembly: System.Reflection.AssemblyInformationalVersion("$(InformationalVersion)")]" />
<ItemGroup>
<Compile Include="$(VersionFileName)" />
</ItemGroup>
</Target>
Remove definitions of the parameters you specify in the generated file from Properties\AssemblyInfo.cs file.
After that you can specify version by adding a parameter to the msbuild:
msbuild /property:Version=1.2.3 /property:InformationalVersion=1.2.3-dev~commithash .\SolutionFile.sln
Update for .NET Core style .csproj files: If you've come upon this question after having transitioned to the new .csproj format used by .NET Core, you can just set the Version property (no need to to bother with MSBuild tasks).
How I finally got this to work MSBuild version 12 (VS 2013).
Used Nuget to get MSBuildTasks Community package
Edited my .csproj file and added a path to the import the package:
<Import Project="..\packages\MSBuildTasks.1.5.0.235\build\MSBuildTasks.targets" Condition="Exists('..\packages\MSBuildTasks.1.5.0.235\build\MSBuildTasks.target')"/>
Figured out the Regex to change just the Revision number in the AssemblyInfo.cs file:
(?<=AssemblyFileVersion\("[0-9]\.[0-9]\.[0-9]\.)(\*)
which is not XML compatible, so has to be changed to:
(?<=AssemblyFileVersion\("[0-9]\.[0-9]\.[0-9]\.)(\*)
Uncommented the <Target Name="BeforeBuild"> section and added the following:
<Target Name="BeforeBuild">
<FileUpdate Files="properties\AssemblyInfo.cs"
Regex="(?<=AssemblyFileVersion\("[0-9]\.[0-9]\.[0-9]\.)(\*)"
ReplacementText="$(Revision)" />
</Target>
When running MSBuild added the "Revision" property to the command line e.g.
msbuild.exe myProject.csproj /t:Build /p:Configuration=Release;Revision=12345

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\\"