如何使用msbuild发布Web应用?

233

Visual Studio 2010有一个发布命令,允许您将Web应用程序项目发布到文件系统位置。我想在我的TeamCity构建服务器上执行此操作,因此我需要使用解决方案运行器或msbuild来完成此操作。我尝试使用Publish目标,但我认为那可能是针对ClickOnce的:

msbuild Project.csproj /t:Publish /p:Configuration=Deploy

我基本上想要做的是与Web部署项目完全相同,但没有插件。 我需要编译WAP,删除任何不必要的执行文件,执行任何web.config转换,并将输出复制到指定位置。

我的解决方案,基于Jeff Siver的答案

<Target Name="Deploy">
    <MSBuild Projects="$(SolutionFile)" 
             Properties="Configuration=$(Configuration);DeployOnBuild=true;DeployTarget=Package" 
             ContinueOnError="false" />
    <Exec Command="&quot;$(ProjectPath)\obj\$(Configuration)\Package\$(ProjectName).deploy.cmd&quot; /y /m:$(DeployServer) -enableRule:DoNotDeleteRule" 
          ContinueOnError="false" />
</Target>

可能重复:https://dev59.com/OnM_5IYBdhLWcg3w8IA2 - Steven Evers
@SnOrfus 我目前正在使用VS 2008中的Web部署项目(正如我在回答那个问题时提到的),但我想尝试自动化VS 2010的发布功能。 - jrummell
2
只需要对您的脚本进行一个小修改:您正在使用$(ProjectPath)来部署脚本,但实际上您需要的是$(ProjectDir),否则您最终会得到.csproj\obj。 - Troy Hunt
@Troy Hunt - ProjectPath 实际上是我脚本中一个变量,它保存着项目文件夹的相对路径,但 ProjectDir 也应该可以使用。 - jrummell
2
从VS2012开始,这变得更容易了:https://dev59.com/m2Yr5IYBdhLWcg3wJ2-U#13947667 - RobSiklos
显示剩余2条评论
12个回答

142

我已经基本上做到了没有自定义的msbuild脚本,以下是相关的TeamCity构建配置设置:

Artifact paths: %system.teamcity.build.workingDir%\MyProject\obj\Debug\Package\PackageTmp 
Runner类型:MSBuild (用于MSBuild文件的运行器)
生成文件路径:MyProject\MyProject.csproj
工作目录:与检出目录相同
MSBuild版本:Microsoft .NET Framework 4.0 
MSBuild ToolsVersion版本:4.0 
运行平台:x86
Targets:Package
传递给MSBuild.exe的命令行参数:/p:Configuration=Debug

这将编译、打包(带有web.config转换)并将输出保存为构件。唯一缺少的是将输出复制到指定位置,但可以通过另一个具有构件依赖项的TeamCity构建配置或使用msbuild脚本来完成。

更新

这里有一个msbuild脚本,将编译、打包(带有web.config转换)并将输出复制到我的临时服务器上。

<?xml version="1.0" encoding="utf-8" ?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
        <SolutionName>MySolution</SolutionName>
        <SolutionFile>$(SolutionName).sln</SolutionFile>
        <ProjectName>MyProject</ProjectName>
        <ProjectFile>$(ProjectName)\$(ProjectName).csproj</ProjectFile>
    </PropertyGroup>

    <Target Name="Build" DependsOnTargets="BuildPackage;CopyOutput" />

    <Target Name="BuildPackage">
        <MSBuild Projects="$(SolutionFile)" ContinueOnError="false" Targets="Rebuild" Properties="Configuration=$(Configuration)" />
        <MSBuild Projects="$(ProjectFile)" ContinueOnError="false" Targets="Package" Properties="Configuration=$(Configuration)" />
    </Target>

    <Target Name="CopyOutput">
        <ItemGroup>
            <PackagedFiles Include="$(ProjectName)\obj\$(Configuration)\Package\PackageTmp\**\*.*"/>
        </ItemGroup>
        <Copy SourceFiles="@(PackagedFiles)" DestinationFiles="@(PackagedFiles->'\\build02\wwwroot\$(ProjectName)\$(Configuration)\%(RecursiveDir)%(Filename)%(Extension)')"/>
    </Target>
</Project>

你也可以从PropertyGroup标签中删除SolutionName和ProjectName属性,并将它们通过msbuild传递。

msbuild build.xml /p:Configuration=Deploy;SolutionName=MySolution;ProjectName=MyProject

更新2

由于这个问题仍然有很多流量,我认为值得更新一下我的答案,介绍我目前使用的脚本,它使用Web Deploy(也称为MSDeploy)。

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build" ToolsVersion="4.0">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
    <ProjectFile Condition=" '$(ProjectFile)' == '' ">$(ProjectName)\$(ProjectName).csproj</ProjectFile>
    <DeployServiceUrl Condition=" '$(DeployServiceUrl)' == '' ">http://staging-server/MSDeployAgentService</DeployServiceUrl>
  </PropertyGroup>

  <Target Name="VerifyProperties">
    <!-- Verify that we have values for all required properties -->
    <Error Condition=" '$(ProjectName)' == '' " Text="ProjectName is required." />
  </Target>

  <Target Name="Build" DependsOnTargets="VerifyProperties">
    <!-- Deploy using windows authentication -->
    <MSBuild Projects="$(ProjectFile)"
             Properties="Configuration=$(Configuration);
                             MvcBuildViews=False;
                             DeployOnBuild=true;
                             DeployTarget=MSDeployPublish;
                             CreatePackageOnPublish=True;
                             AllowUntrustedCertificate=True;
                             MSDeployPublishMethod=RemoteAgent;
                             MsDeployServiceUrl=$(DeployServiceUrl);
                             SkipExtraFilesOnServer=True;
                             UserName=;
                             Password=;"
             ContinueOnError="false" />
  </Target>
</Project>
在TeamCity中,我有名为env.Configurationenv.ProjectNameenv.DeployServiceUrl的参数。MSBuild运行程序具有构建文件路径,并且参数会自动传递(您无需在命令行参数中指定它们)。

您还可以从命令行中运行它:

msbuild build.xml /p:Configuration=Staging;ProjectName=MyProject;DeployServiceUrl=http://staging-server/MSDeployAgentService

2
谢谢 - 这也可以直接从PowerShell中很好地工作(对于格式不当表示歉意 - 注释中没有回车符): &msbuild "$solution" /p:"Configuration=$configuration" ; &msbuild "$project" /t:Package /p:"Configuration=$configuration;_PackageTempDir=$outputfolder" - zcrar70
@jrummell:我想从TeamCity将我的Visual Studio Web项目部署到远程Windows服务器上。我该怎么办?我是初学者,对该如何操作一无所知。 - Nevin Raj Victor
1
我能够在TeamCity上使用Web应用程序项目使其工作,但我还有一个遗留的绑定网站项目也需要发布(作为一个包),然后需要使用MSDeploy。如果我在VS2013中发布,我会得到一个部署包,但是从cmd行中使用MSBuild不会创建一个。有什么想法吗? - KnowHowSolutions
@KnowHowSolutions 我不确定这种方法是否适用于网站项目。我只尝试过在Web应用程序项目中使用它。 - jrummell
1
我没有看到这方面有任何提及。应该指定发布配置文件,以便应用正确的 web.config 转换。更新:算了吧...这个功能是在这篇文章发表两年后才引入的。这篇文章中提到的方法仍然可能有效。该线程中稍后的帖子显示了如何从命令行使用发布配置文件进行发布。 - Triynko
显示剩余7条评论

92
使用在VS 2012中引入的部署配置文件,您可以使用以下命令行进行发布:


msbuild MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=<profile-name> /p:Password=<insert-password> /p:VisualStudioVersion=11.0

有关参数的更多信息,请参见此文档

/p:VisualStudioVersion参数的值取决于您使用的Visual Studio版本。维基百科有一张Visual Studio发行版及其版本的表格


8
在使用VS2012 .NET 3.5时,将程序部署到文件系统失败。它只是进行编译而没有进行部署。 - Jay Sullivan
2
你的 /p:VisualStudioVersion=11.0 拯救了我的生命。我在 vs2013 中使用 /p:VisualStudioVersion=12.0,它运行良好。 - Seyed Morteza Mousavi
在VS 2017中,/p:VisualStudioVersion=? 的值将是多少? - Nishant
创建了构建脚本 msbuild test.sln /p:DeployOnBuild=True /p:DeployDefaultTarget=WebPublish /p:WebPublishMethod=FileSystem /p:DeleteExistingFiles=True /p:publishUrl=.\build_output1\pub /p:PublishProfile=FolderProfile /p:VisualStudioVersion=11.0 /p:outdir=.\build_output1,但仍然只得到 DLL 文件而不是像在发布文件夹中那样得到所有的文件。 :( - Nishant
1
@Nishant 对于VS 2017,请使用/p:VisualStudioVersion=15。我不确定这是否与您的文件复制问题有关。 - Chris

43
我想出了这样的解决方案,对我来说非常有效:

我想出了这样的解决方案,对我来说非常有效:

msbuild /t:ResolveReferences;_WPPCopyWebApplication /p:BuildingProject=true;OutDir=C:\Temp\build\ Test.csproj

秘密武器是_WPPCopyWebApplication目标。

2
什么是_WPPCopyWebApplication?我怎样才能在MSBuild xml配置文件中使用它? - Johnny_D
4
在使用VS2012 .NET 3.5时,我遇到了错误 error MSB4057: The target "_WPPCopyWebApplication" does not exist in the project。移除该部分后,导致部署没有部署任何视图。 - Jay Sullivan
你可能需要使用不同的/p:VisualStudioVersion=12.0来调用它,因为构建使用了c:\program files (x86)\msbuild\microsoft\visualstudio\VERSION\Webapplication\Microsoft.WebApplication.targets中的目标,所以可能正在使用一个旧版本,该版本没有正确的目标。 - Jim Wolff
@FRoZeN 我尝试使用MSBuild作为 MSBuild.exe C:\BuildAgent\work\4c7b8ac8bc7d723e\WebService.sln /p:Configuration=Release /p:OutputPath=bin /p:DeployOnBuild=True /p:DeployTarget=MSDeployPublish /p:MsDeployServiceUrl=https://204.158.674.5/msdeploy.axd /p:username=Admin /p:password=Password#321 /p:AllowUntrustedCertificate=True /p:DeployIisAppPath=Default WebSite/New /p:MSDeployPublishMethod=WMSVC。但是它给我一个错误 MSBUILD:error MSB1008:只能指定一个项目。开关:WebSite/New。这个问题有解决方案吗? - Nevin Raj Victor
1
@NevinRajVictor,这个错误很可能是因为在DeployIisAppPath值中有一个空格。你需要将该值放在引号中。例如:/p:DeployIisAppPath="Default Website/New" - shiitake

29

我不熟悉TeamCity,但希望这个方法对您有用。

我发现使用MSDeploy.exe是最好的方法。它是Microsoft运行的WebDeploy项目的一部分,您可以在这里下载它。

使用WebDeploy,您可以运行命令行:

msdeploy.exe -verb:sync -source:contentPath=c:\webApp -dest:contentPath=c:\DeployedWebApp

该代码与VS中的“发布”命令执行相同操作,只复制必要的文件到部署文件夹中。


看起来很有前途。但是,管理服务似乎只能在Server 2008上使用。我想自动化部署的暂存服务器正在运行Windows 7 Pro。 - jrummell
2
该产品由两部分组成。与IIS集成的部分需要Server 2008支持。而命令行组件则不需要该要求;我已经在一个用于部署的Server 2003盒子上运行了该组件。 - Jeff Siver
我已经阅读了有关 MSDeploy 的一些内容。我已经在我的分阶段服务器上安装并运行它,谢谢!我能否从 MSBuild 脚本中运行 MSDeploy? - jrummell
它应该作为构建脚本中的EXEC任务正常运行。 - Jeff Siver
1
它与VS发布命令的哪个配置执行相同的操作?哪种发布方法-文件系统还是其他?它是否使用MyProject.Publish.xml文件来确定要复制哪些文件? - Anthony
1
我刚试了一下,但它没有像VS发布那样做。它和XCopy一样,包括所有源文件。 - Louis Somers

13
使用VisualStudio 2012,有一种处理subj的方法,不需要发布配置文件。您可以使用参数传递输出文件夹。在“publishUrl”参数中,绝对路径和相对路径都可以使用。您可以使用VS100COMNTOOLS,但是您需要覆盖VisualStudioVersion,以使用目标'WebPublish',该目标位于%ProgramFiles%\MSBuild\Microsoft\VisualStudio\v11.0\WebApplications\Microsoft.WebApplication.targets中。对于VisualStudioVersion 10.0,此脚本将成功执行而无需输出:)
更新:我已成功在仅安装Windows SDK 7.1(没有Visual Studio 2010和2012)的构建服务器上使用此方法。但是,我必须按照以下步骤才能使其正常工作:
  1. 使用Simmo答案(https://dev59.com/DHE85IYBdhLWcg3whUBr#2907056)使Windows SDK 7.1成为机器上的当前版本
  2. 将注册表键HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7\10.0设置为“C:\Program Files\Microsoft Visual Studio 10.0\"(根据情况使用您的路径)
  3. 将%ProgramFiles%\MSBuild\Microsoft\VisualStudio\v11.0文件夹从我的开发者机器复制到构建服务器
脚本:
set WORK_DIR=%~dp0
pushd %WORK_DIR%
set OUTPUTS=%WORK_DIR%..\Outputs
set CONFIG=%~1
if "%CONFIG%"=="" set CONFIG=Release
set VSTOOLS="%VS100COMNTOOLS%"
if %VSTOOLS%=="" set "PATH=%PATH%;%WINDIR%\Microsoft.NET\Framework\v4.0.30319" && goto skipvsinit
call "%VSTOOLS:~1,-1%vsvars32.bat"
if errorlevel 1 goto end
:skipvsinit
msbuild.exe Project.csproj /t:WebPublish /p:Configuration=%CONFIG% /p:VisualStudioVersion=11.0 /p:WebPublishMethod=FileSystem /p:publishUrl=%OUTPUTS%\Project
if errorlevel 1 goto end
:end
popd
exit /b %ERRORLEVEL%

谢谢您提供的解决方案 - 这正是我在寻找的:使用文件系统部署的WebPublish选项。 - scrat.squirrel

12

我找到了两种不同的解决方案,它们的工作方式略有不同:

1. 这个解决方案是受 alexanderb 的答案启发的[link]。不幸的是,它对我们没有用 - 一些 dll 没有复制到 OutDir。我们发现将 ResolveReferences 替换为 Build 目标可以解决这个问题 - 现在所有必要的文件都被复制到了 OutDir 位置。

msbuild /target:Build;_WPPCopyWebApplication  /p:Configuration=Release;OutDir=C:\Tmp\myApp\ MyApp.csproj
这个解决方案的缺点是 OutDir 包含的不仅仅是发布所需的文件。

2. 第一种解决方案效果不错,但不符合我们的期望。我们希望发布功能与Visual Studio IDE中的相同 - 即只有应该发布的文件才会被复制到输出目录中。正如之前提到的,第一种解决方案将更多的文件复制到了OutDir中 - 网站发布后存储在_PublishedWebsites/{ProjectName}子文件夹中。以下命令可以解决这个问题 - 只有发布所需的文件才会被复制到所需的文件夹中。因此,现在您有一个可以直接发布的目录 - 与第一种解决方案相比,您可以节省硬盘空间。
msbuild /target:Build;PipelinePreDeployCopyAllFilesToOneFolder /p:Configuration=Release;_PackageTempDir=C:\Tmp\myApp\;AutoParameterizationWebConfigConnectionStrings=false MyApp.csproj
AutoParameterizationWebConfigConnectionStrings=false参数将确保连接字符串不被处理为特殊工件,并且将被正确生成 - 有关详细信息,请参见link

你的第二个选项帮助我轻松地摆脱了过时的_CopyWebApplication。在升级到VS 2015后,你拯救了我的Build-Server。非常感激你的出色研究。 - it3xl
你的第二个选项非常适合我的构建脚本。 - AnthonyVO

5
这是我的工作批处理文件。

发布网站批处理文件(publish-my-website.bat)

SET MSBUILD_PATH="C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin"
SET PUBLISH_DIRECTORY="C:\MyWebsitePublished"
SET PROJECT="D:\Github\MyWebSite.csproj"


cd /d %MSBUILD_PATH%
MSBuild %PROJECT%  /p:DeployOnBuild=True /p:DeployDefaultTarget=WebPublish /p:WebPublishMethod=FileSystem /p:DeleteExistingFiles=True /p:publishUrl=%PUBLISH_DIRECTORY%

请注意,我在服务器上安装了Visual Studio以便运行MsBuild.exe,因为.Net Framework文件夹中的MsBuild.exe无法工作。

1
msbuild test.sln /p:DeployOnBuild=True /p:DeployDefaultTarget=WebPublish /p:WebPublishMethod=FileSystem /p:DeleteExistingFiles=True /p:publishUrl=.\build_output1\pub /p:PublishProfile=FolderProfile /p:VisualStudioVersion=11.0 /p:outdir=.\build_output1......但是我仍然只得到DLL文件,而不是我想要的文件结构。这是怎么回事?:( - Nishant

3
您必须设置以下环境变量:
  • <网站名称>
  • <域名>
并参考我的博客。(抱歉,该文章为韩文)
  • http://xyz37.blog.me/50124665657
  • http://blog.naver.com/PostSearchList.nhn?SearchText=webdeploy&blogId=xyz37&x=25&y=7

    @ECHO OFF
    :: https://dev59.com/4W035IYBdhLWcg3wJccw
    ::-DeployOnBuild -True
    :: -False
    :: 
    ::-DeployTarget -MsDeployPublish
    :: -Package
    :: 
    ::-Configuration -Name of a valid solution configuration
    :: 
    ::-CreatePackageOnPublish -True
    :: -False
    :: 
    ::-DeployIisAppPath -<Web Site Name>/<Folder>
    :: 
    ::-MsDeployServiceUrl -Location of MSDeploy installation you want to use
    :: 
    ::-MsDeployPublishMethod -WMSVC (Web Management Service)
    :: -RemoteAgent
    :: 
    ::-AllowUntrustedCertificate (used with self-signed SSL certificates) -True
    :: -False
    :: 
    ::-UserName
    ::-Password
    SETLOCAL
    
    IF EXIST "%SystemRoot%\Microsoft.NET\Framework\v2.0.50727" SET FXPath="%SystemRoot%\Microsoft.NET\Framework\v2.0.50727"
    IF EXIST "%SystemRoot%\Microsoft.NET\Framework\v3.5" SET FXPath="%SystemRoot%\Microsoft.NET\Framework\v3.5"
    IF EXIST "%SystemRoot%\Microsoft.NET\Framework\v4.0.30319" SET FXPath="%SystemRoot%\Microsoft.NET\Framework\v4.0.30319"
    
    SET targetFile=<web site fullPath ie. .\trunk\WebServer\WebServer.csproj
    SET configuration=Release
    SET msDeployServiceUrl=https://<domain>:8172/MsDeploy.axd
    SET msDeploySite="<WebSite name>"
    SET userName="WebDeploy"
    SET password=%USERNAME%
    SET platform=AnyCPU
    SET msbuild=%FXPath%\MSBuild.exe /MaxCpuCount:%NUMBER_OF_PROCESSORS% /clp:ShowCommandLine
    
    %MSBuild% %targetFile% /p:configuration=%configuration%;Platform=%platform% /p:DeployOnBuild=True /p:DeployTarget=MsDeployPublish /p:CreatePackageOnPublish=False /p:DeployIISAppPath=%msDeploySite% /p:MSDeployPublishMethod=WMSVC /p:MsDeployServiceUrl=%msDeployServiceUrl% /p:AllowUntrustedCertificate=True /p:UserName=%USERNAME% /p:Password=%password% /p:SkipExtraFilesOnServer=True /p:VisualStudioVersion=12.0
    
    IF NOT "%ERRORLEVEL%"=="0" PAUSE 
    ENDLOCAL
    

2
以下是翻译的结果:

您可以使用以下代码将解决方案发布到所需路径,其中PublishInDFolder是需要发布的路径名称(我们需要在下面的图片中创建)

您可以像这样创建发布文件

在批处理文件(.bat)中添加以下2行代码

@echo OFF 
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsMSBuildCmd.bat"
MSBuild.exe  D:\\Solution\\DataLink.sln /p:DeployOnBuild=true /p:PublishProfile=PublishInDFolder
pause

1

这是我的批处理文件

C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe C:\Projects\testPublish\testPublish.csproj  /p:DeployOnBuild=true /property:Configuration=Release
if exist "C:\PublishDirectory" rd /q /s "C:\PublishDirectory"
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe -v / -p C:\Projects\testPublish\obj\Release\Package\PackageTmp -c C:\PublishDirectory
cd C:\PublishDirectory\bin 
del *.xml
del *.pdb

5
如果您能详细说明,那就太好了。您的批处理文件是如何解决问题的呢?谢谢! - Luís Cruz
@LuísCruz,我猜他使用aspnet_compiler工具进行部署。 - andreikashin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接