42

I'm trying to deploy one of the web projects in my solution to a server. I am using msbuild on TeamCity like so:

msbuild MySolution.sln /t:WebSite:Rebuild /p:DeployOnBuild=True /p:PublishProfile=Prod ...

However, when I run it, msbuild still tries to build my WebService project, even though my WebSite project does not depend on it (but it does depend on a Services project also in the solution). How do only publish one project, aka just WebSite?

I have also tried building the project file using

msbuild WebSite/WebSite.csproj /p:DeployOnBuild=True ...

but it then complains that it can't restore packages:

[07:47:17]WebSite\WebSite.csproj.teamcity: Build target: Build
[07:47:17][WebSite\WebSite.csproj.teamcity] RestorePackages
[07:47:17][RestorePackages] Exec
[07:47:17][Exec] C:\TeamCity\buildAgent\work\cab8a3d752df3a51\.nuget\NuGet.targets(90, 15): error MSB4064: The "LogStandardErrorAsError" parameter is not supported by the "Exec" task. Verify the parameter exists on the task, and it is a settable public instance property.
[07:47:17][Exec] C:\TeamCity\buildAgent\work\cab8a3d752df3a51\.nuget\NuGet.targets(89, 9): error MSB4063: The "Exec" task could not be initialized with its input parameters. 
[07:47:17][WebSite\WebSite.csproj.teamcity] Project WebSite\WebSite.csproj.teamcity failed.

When I disable NuGet Package Restore, CoreCompile (Csc) fails with errors I've never heard of and shouldn't be happening:

[07:54:43]WebSite\WebSite.csproj.teamcity: Build target: Build (13s)
[07:54:55][WebSite\WebSite.csproj.teamcity] CoreCompile
[07:54:55][CoreCompile] Csc
[07:54:56][Csc] Areas\Api\Services\TripService.cs(19, 104): error CS0241: Default parameter specifiers are not permitted
[07:54:56][Csc] Helpers\StatisticsUtility.cs(11, 35): error CS1031: Type expected
[07:54:56][Csc] Helpers\StatisticsUtility.cs(11, 53): error CS1002: ; expected
[07:54:56][Csc] Helpers\StatisticsUtility.cs(16, 28): error CS1519: Invalid token '(' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(16, 37): error CS1519: Invalid token ',' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(17, 27): error CS1519: Invalid token '(' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(17, 32): error CS1519: Invalid token ')' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(23, 17): error CS1519: Invalid token 'for' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(23, 26): error CS1519: Invalid token '<=' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(23, 45): error CS1519: Invalid token '-' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(23, 51): error CS1519: Invalid token '++' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(24, 34): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression)
[07:54:56][Csc] Helpers\StatisticsUtility.cs(24, 37): error CS1519: Invalid token '==' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(24, 51): error CS1519: Invalid token ')' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(24, 63): error CS1519: Invalid token '++' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(25, 41): error CS1519: Invalid token '>' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(25, 53): error CS1519: Invalid token ')' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(27, 36): error CS1519: Invalid token '=' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(27, 48): error CS1519: Invalid token ';' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(28, 36): error CS1519: Invalid token '=' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(29, 37): error CS1519: Invalid token '=' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(29, 48): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression)
[07:54:56][Csc] Helpers\StatisticsUtility.cs(29, 50): error CS1519: Invalid token ';' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(30, 33): error CS1519: Invalid token '=' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(30, 44): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression)
[07:54:56][Csc] Helpers\StatisticsUtility.cs(30, 50): error CS1519: Invalid token ';' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\StatisticsUtility.cs(32, 21): error CS0116: A namespace does not directly contain members such as fields or methods
[07:54:56][Csc] Helpers\StatisticsUtility.cs(35, 50): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\StatisticsUtility.cs(38, 21): error CS0116: A namespace does not directly contain members such as fields or methods
[07:54:56][Csc] Helpers\StatisticsUtility.cs(40, 50): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\StatisticsUtility.cs(42, 21): error CS1022: Type or namespace definition, or end-of-file expected
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(8, 59): error CS1031: Type expected
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(8, 80): error CS1002: ; expected
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(10, 55): error CS1519: Invalid token '(' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(10, 60): error CS1520: Class, struct, or interface method must have a return type
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(10, 82): error CS1002: ; expected
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(13, 23): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(15, 60): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(18, 23): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(20, 25): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(23, 28): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(26, 28): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(29, 24): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(29, 84): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(32, 28): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(35, 9): error CS1022: Type or namespace definition, or end-of-file expected
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(23, 26): error CS0101: The namespace '<global namespace>' already contains a definition for '?'
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(26, 26): error CS0101: The namespace '<global namespace>' already contains a definition for '?'
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(29, 22): error CS0101: The namespace '<global namespace>' already contains a definition for '?'
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(29, 83): error CS0101: The namespace '<global namespace>' already contains a definition for '?'
[07:54:56][Csc] Helpers\UrlHelperExtensions.cs(32, 26): error CS0101: The namespace '<global namespace>' already contains a definition for '?'
[07:54:56][Csc] Controllers\SessionController.cs(13, 51): error CS0241: Default parameter specifiers are not permitted
[07:54:56][Csc] Helpers\JsonNetResult.cs(13, 44): error CS1031: Type expected
[07:54:56][Csc] Helpers\JsonNetResult.cs(13, 72): error CS1041: Identifier expected, 'object' is a keyword
[07:54:56][Csc] Helpers\JsonNetResult.cs(13, 91): error CS1002: ; expected
[07:54:56][Csc] Helpers\JsonNetResult.cs(16, 38): error CS1519: Invalid token '=' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\JsonNetResult.cs(16, 59): error CS1519: Invalid token ';' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\JsonNetResult.cs(17, 64): error CS1519: Invalid token '=' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\JsonNetResult.cs(17, 90): error CS1519: Invalid token ';' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\JsonNetResult.cs(18, 32): error CS1519: Invalid token '=' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\JsonNetResult.cs(18, 46): error CS1519: Invalid token ';' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\JsonNetResult.cs(19, 33): error CS1519: Invalid token ';' in class, struct, or interface member declaration
[07:54:56][Csc] Helpers\JsonNetResult.cs(22, 23): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\JsonNetResult.cs(25, 37): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\JsonNetResult.cs(32, 23): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\JsonNetResult.cs(35, 37): error CS1518: Expected class, delegate, enum, interface, or struct
[07:54:56][Csc] Helpers\JsonNetResult.cs(40, 9): error CS1022: Type or namespace definition, or end-of-file expected
[07:54:56][Csc] Mailers\ITripMailer.cs(13, 132): error CS0241: Default parameter specifiers are not permitted
[07:54:56][Csc] Mailers\TripMailer.cs(54, 85): error CS0241: Default parameter specifiers are not permitted
[07:54:56][Csc] Services\Impl\AuthorizationService.cs(12, 70): error CS0241: Default parameter specifiers are not permitted
[07:54:56][Csc] Services\Impl\AuthorizationService.cs(43, 77): error CS0241: Default parameter specifiers are not permitted
[07:54:56][WebSite\WebSite.csproj.teamcity] Project WebSite\WebSite.csproj.teamcity failed.
Caleb Jares
  • 5,632
  • 6
  • 49
  • 80

3 Answers3

63

I blogged about this at http://sedodream.com/2013/03/06/HowToPublishOneWebProjectFromASolution.aspx a few months back. I've copied the details here as well, see below.


Today on twitter @nunofcosta asked me roughly the question “How do I publish one web project from a solution that contains many?”

The issue that he is running into is that he is building from the command line and passing the following properties to msbuild.exe.

/p:DeployOnBuild=true
/p:PublishProfile='siteone - Web Deploy'
/p:Password=%password%

You can read more about how to automate publishing at http://sedodream.com/2013/01/06/CommandLineWebProjectPublishing.aspx.

When you pass these properties to msbuild.exe they are known as global properties. These properties are difficult to override and are passed to every project that is built. Because of this if you have a solution with multiple web projects, when each web project is built it is passed in the same set of properties. Because of this when each project is built the publish process for that project will start and it will expect to find a file named siteone – Web Deploy.pubxml in the folder *Properties\PublishProfiles*. If the file doesn’t exist the operation may fail.

Note: If you are interested in using this technique for an orchestrated publish see my comments at https://stackoverflow.com/a/14231729/105999 before doing so.

So how can we resolve this?

Let’s take a look at a sample (see links below). I have a solution, PublishOnlyOne, with the following projects.

  1. ProjA
  2. ProjB

ProjA has a publish profile named ‘siteone – Web Deploy’, ProjB does not. When trying to publish this you may try the following command line.

msbuild.exe PublishOnlyOne.sln /p:DeployOnBuild=true /p:PublishProfile=’siteone – Web Deploy’ /p:Password=%password%

See publish-sln.cmd in the samples.

If you do this, when its time for ProjB to build it will fail because there’s no siteone – Web Deploy profile for that project. Because of this, we cannot pass DeployOnBuild. Instead here is what we need to do.

  1. Edit ProjA.csproj to define another property which will conditionally set DeployOnBuild
  2. From the command line pass in that property

I edited ProjA and added the following property group before the Import statements in the .csproj file.

<PropertyGroup>
<DeployOnBuild Condition=" '$(DeployProjA)'!='' ">$(DeployProjA)</DeployOnBuild>
</PropertyGroup>

Here you can see that DeployOnBuild is set to whatever value DeployProjA is as long as it’s not empty. Now the revised command is:

msbuild.exe PublishOnlyOne.sln /p:DeployProjA=true /p:PublishProfile=’siteone – Web Deploy’ /p:Password=%password%

Here instead of passing DeployOnBuild, I pass in DeployProjA which will then set DeployOnBuild. Since DeployOnBuild wasn’t passed to ProjB it will not attempt to publish.

You can find the complete sample at https://github.com/sayedihashimi/sayed-samples/tree/master/PublishOnlyOne.

Community
  • 1
  • 1
Sayed Ibrahim Hashimi
  • 42,483
  • 14
  • 139
  • 172
  • Nice writeup! This definitely makes sense. However, I ended up solving my problem by creating an msbuild file based on another question on SO: http://stackoverflow.com/questions/3097489/how-to-publish-web-with-msbuild – Caleb Jares Jun 03 '13 at 19:50
  • 1
    This was a very clever answer, and I wanted to thank you very much for it. It solved a serious problem for me! – Matt DiTrolio Jun 13 '13 at 23:48
  • Wonderful! This is exactly what I needed and worked perfectly, thank for the answer and great blog post – Andy Mehalick Aug 13 '15 at 08:07
  • I am trying to use the same approach to deploy a clickonce project I have among many other project I do not want to deploy. However, I get a warning from VS IDE when I try to DeployOnBuild property on .csproj. The build seems to ignore this property and no deployment takes place. How can I fix that? – Igor Kondrasovas Sep 01 '15 at 17:02
  • @IgorKondrasovas what do you mean you get an error? Do you mean that it's squiggled in the editor? If so you can safely ignore that. – Sayed Ibrahim Hashimi Sep 02 '15 at 17:23
  • @SayedIbrahimHashimi I mean the visual studio editor says the PropertyGroup has invalid child elements and shows me a list of expected values. If I can ignore this warning, then how can I find the deployment success (of fail) on the build log? I can't see anything there.... – Igor Kondrasovas Sep 03 '15 at 09:27
  • @SayedIbrahimHashimi I had a look on the console output during build and it seems the only publish-related thing done is to copy my app .exe file to a app.publish folder. I think the reason is I am not specifying any publish profile. Wpf apps publish wizard on VS does not support "profiles".. – Igor Kondrasovas Sep 03 '15 at 10:27
  • @IgorKondrasovas this answer only applies to web projects. DeployOnBuild and PublishProfiles are web specific properties. – Sayed Ibrahim Hashimi Sep 03 '15 at 10:32
  • Too complex, see 'IsPublishable' answer below – TarmoPikaro May 18 '21 at 21:03
  • @TarmoPikaro there is nothing complex here, it's a single property added to the project. The length of the answer is because I included details so people can fully understand what is happening. FYI I believe that IsPublishable doesn't apply for .NET Framework (not .net core or .net 5+) projects. – Sayed Ibrahim Hashimi May 20 '21 at 02:25
  • If you use old .net framework project format, then yes - most probably IsPublishable will not work for you. But it's also possible to use SDK based project format (.net core) with .net framework (TargetFramework = net48). – TarmoPikaro May 20 '21 at 21:00
29

There is a much simpler solution for this. MSBuild supports targeting a single project while building the solution. You do this by putting the project name in the Target parameter. Note that this is the visual name of the project you specify in the solution (not necessarily the same as the name of the .csproj file).

Note: The only "trick" needed here is to replace the dots (.) in the project name with underscores (_).

Example MSBuild command line, if your project name is "Your.Project.Name":

msbuild.exe YourSolutionName.sln /T:"Your_Poject_Name" /P:DeployOnBuild=true /P:PublishProfile=YourPublishProfile.pubxml

You may also specify a build target for that project, but this target should exist for all projects in the solution:

msbuild.exe YourSolutionName.sln /T:"Your_Poject_Name:Rebuild" /P:DeployOnBuild=true /P:PublishProfile=YourPublishProfile.pubxml

Sources

  1. This is partially documented in MSDN since Visual Studio 2008: https://msdn.microsoft.com/en-us/library/ms164311(v=vs.140).aspx
  2. Special thanks to Vasil Trifonov for pointing out the replacement trick: http://www.codeproject.com/Articles/654910/How-to-build-a-specific-project-from-a-solution-wi
arni
  • 1,896
  • 16
  • 12
  • 1
    This works, but does not appear to build all the dependencies of the web project. I tested this by referencing a class library and then running the msbuild command. It errored saying that it could not find the library. – Remotec Nov 14 '16 at 14:34
  • This should work as we're using this technique in serveral CI configurations (VS2015). Make sure your class library is set to "Build" under the respective solution configuration (which is in turn selected in the publish profile). – arni Dec 04 '16 at 12:33
  • I know this is dated - but I too have tried this approach using a WinForms application. It does indeed build the dependencies. My problem is I am overriding the ProductName and AssemblyName properties in the MSBuild command. The assembly name gets applied to ALL dependent assemblies. I only want to apply it to the winforms project. https://stackoverflow.com/questions/55447528/building-a-win-forms-application-with-dependent-projects-and-overriding-publish – JDBennett Apr 01 '19 at 12:14
  • When using this solution with Azure DevOps, you need to remove the quotation marks, otherwise an error is thrown – uniquelau Dec 30 '19 at 17:19
1

Another option which is better in scenario that requires manual customization of publishing, is to use IsPublishable MSBuild property (found it here https://github.com/dotnet/docs/issues/13365):

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>

    <IsPublishable>false</IsPublishable>
  </PropertyGroup>
...
</Project>

MSBuild conditions could be used for setting IsPublishable value according to different flows, for example:

    <IsPublishable Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'>false</IsPublishable>
MaMazav
  • 1,443
  • 1
  • 13
  • 29
  • I see a value in this answer here although other answers are more appropriate for the specific asked question: I encountered this question when searching for such customization scenarios and I believe I'm not the only one. – MaMazav Sep 08 '20 at 06:38