Usando msbuild para executar um Perfil de Publicação de Sistema de Arquivos

86

Tenho um projeto c # .Net 4.0 criado com VS2010 e agora sendo acessado com VS2012.

Estou tentando publicar apenas os arquivos necessários deste site para um local de destino (C: \ builds \ MyProject [Files])

Minha estrutura de arquivo: ./ProjectRoot/MyProject.csproj ./ProjectRoot/Properties/PublishProfiles/FileSystemDebug.pubxml

Estou executando o seguinte por meio do MSBuild:

C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ MSBuild.exe ./ProjectRoot/MyProject.csproj / p: DeployOnBuild = true /p:PublishProfile=./ProjectRoot/Properties/PublishProfiles/FileSystemDebug.pubxml

Aqui está o xml em FileSystemDebug.pubxml

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <WebPublishMethod>FileSystem</WebPublishMethod>
    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>
    <SiteUrlToLaunchAfterPublish />
    <ExcludeApp_Data>False</ExcludeApp_Data>
    <publishUrl>C:\builds\MyProject\</publishUrl>
    <DeleteExistingFiles>True</DeleteExistingFiles>
  </PropertyGroup>
</Project>

O comportamento resultante é:

  • um arquivo zip é criado aqui: ./ProjectRoot/obj/Debug/Package/MyProject.zip
  • Nada é implantado no <publishUrl>C:\builds\MyProject\</publishUrl>WTF
  • o arquivo zip que é criado é um café da manhã dos porcos e cheio de arquivos desnecessários para o aplicativo.

Quando executo este perfil de publicação por meio do Visual Studio, uma pasta é criada em * C: \ builds \ MyProject * e contém os artefatos exatos que desejo.

Como faço para obter este resultado simples do msbuild?

P. Roe
fonte

Respostas:

51

Para sua informação: Eu tive o mesmo problema com o Visual Studio 2015. Depois de muitas horas tentando, agora posso fazer msbuild myproject.csproj /p:DeployOnBuild=true /p:PublishProfile=myprofile.

Tive que editar meu arquivo .csproj para fazê-lo funcionar. Ele continha uma linha como esta:

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" 
  Condition="false" />

Eu mudei esta linha da seguinte maneira:

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v14.0\WebApplications\Microsoft.WebApplication.targets" />

(Eu mudei 10.0 para 14.0, não tenho certeza se isso era necessário. Mas eu definitivamente tive que remover a parte da condição.)

johanv
fonte
1
A importação condicional com Condition="false"existe para compatibilidade com versões anteriores. O VS2010 requer que esta importação exista, mesmo se for ignorada devido à condição falsa. Se você olhar novamente, verá que o csproj contém outra importação para a $(VSToolsPath)\WebApplications\Microsoft.WebApplication.targetsqual resolve o arquivo de destino da versão atual do Visual Studio.
Steven Liekens
3
Observe o uso estratégico de $(MSBuildToolsVersion)no caminho para a conta para a versão adequada VS: <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(MSBuildToolsVersion)\WebApplications\Microsoft.WebApplication.targets" Condition="false" />. Isso funcionou para mim na atualização 1 do VS2015.
Al Dass
42

Encontre a resposta aqui: http://www.digitallycreated.net/Blog/59/locally-publishing-a-vs2010-asp.net-web-application-using-msbuild

O Visual Studio 2010 tem excelentes novos recursos de publicação de Projeto de Aplicativo da Web que permitem que você publique facilmente seu projeto de aplicativo da Web com o clique de um botão. Nos bastidores, a transformação Web.config e a construção do pacote são feitas por um script MSBuild massivo que é importado para o arquivo de projeto (encontrado em: C: \ Arquivos de programas (x86) \ MSBuild \ Microsoft \ VisualStudio \ v10.0 \ Web \ Microsoft .Web.Publishing.targets). Infelizmente, o script é extremamente complicado, confuso e não documentado (além de alguns comentários mal ortográficos e quase sempre inúteis no arquivo). Um grande fluxograma desse arquivo e alguma documentação sobre como conectá-lo seria bom, mas parece estar faltando (ou pelo menos não consigo encontrar).

Infelizmente, isso significa que a publicação por meio da linha de comando é muito mais opaca do que precisa ser. Fiquei surpreso com a falta de documentação nesta área, porque hoje em dia muitas lojas usam um servidor de integração contínua e algumas até fazem implantação automatizada (na qual os recursos de publicação do VS2010 poderiam ajudar muito), então pensei que habilitar isso ( facilmente!) seria um requisito bastante principal para o recurso.

De qualquer forma, depois de vasculhar o arquivo Microsoft.Web.Publishing.targets por horas e bater minha cabeça contra a parede de tentativa e erro, consegui descobrir como o Visual Studio parece realizar sua mágica com um clique “Publicar no sistema de arquivos” e recursos de “Build Deployment Package”. Entrarei em contato com o script do MSBuild, portanto, se você não estiver familiarizado com o MSBuild, sugiro que verifique esta página do MSDN do curso intensivo.

Publicar no sistema de arquivos

A caixa de diálogo Publicar no sistema de arquivos VS2010 Publicar no sistema de arquivos demorou um pouco para entender porque esperava que algum uso sensato do MSBuild estivesse ocorrendo. Em vez disso, o VS2010 faz algo bastante estranho: ele chama o MSBuild para realizar uma espécie de meia implantação que prepara os arquivos do aplicativo da web na pasta obj do seu projeto, então parece fazer uma cópia manual desses arquivos (ou seja, fora do MSBuild) em sua pasta de publicação de destino. Este é um comportamento realmente estranho porque o MSBuild foi projetado para copiar arquivos (e outras coisas relacionadas à compilação), então faria sentido se todo o processo fosse apenas um destino MSBuild que o VS2010 chamou, não um destino, mas uma cópia manual.

Isso significa que fazer isso por meio do MSBuild na linha de comando não é tão simples quanto invocar seu arquivo de projeto com um destino específico e definir algumas propriedades. Você precisará fazer o que o VS2010 deveria ter feito: crie você mesmo um destino que execute a implantação parcial e copie os resultados para a pasta de destino. Para editar seu arquivo de projeto, clique com o botão direito do mouse no projeto no VS2010 e clique em Unload Project, então clique com o botão direito novamente e clique em Edit. Role para baixo até encontrar o elemento Import que importa os destinos do aplicativo da web (Microsoft.WebApplication.targets; este arquivo importa o arquivo Microsoft.Web.Publishing.targets mencionado anteriormente). Abaixo dessa linha, adicionaremos nosso novo destino, chamado PublishToFileSystem:

<Target Name="PublishToFileSystem"
        DependsOnTargets="PipelinePreDeployCopyAllFilesToOneFolder">
    <Error Condition="'$(PublishDestination)'==''"
           Text="The PublishDestination property must be set to the intended publishing destination." />
    <MakeDir Condition="!Exists($(PublishDestination))"
             Directories="$(PublishDestination)" />

    <ItemGroup>
        <PublishFiles Include="$(_PackageTempDir)\**\*.*" />
    </ItemGroup>

    <Copy SourceFiles="@(PublishFiles)"
          DestinationFiles="@(PublishFiles->'$(PublishDestination)\%(RecursiveDir)%(Filename)%(Extension)')"
          SkipUnchangedFiles="True" />
</Target>

Esse destino depende do destino PipelinePreDeployCopyAllFilesToOneFolder, que é o que o VS2010 chama antes de fazer sua cópia manual. Algumas pesquisas em Microsoft.Web.Publishing.targets mostram que a chamada desse destino faz com que os arquivos do projeto sejam colocados no diretório especificado pela propriedade _PackageTempDir.

A primeira tarefa que chamamos em nosso destino é a tarefa Error, sobre a qual colocamos uma condição que garante que a tarefa só aconteça se a propriedade PublishDestination não tiver sido definida. Isso irá detectar você e errar na compilação caso tenha esquecido de especificar a propriedade PublishDestination. Em seguida, chamamos a tarefa MakeDir para criar esse diretório PublishDestination se ele ainda não existir.

Em seguida, definimos um item chamado PublishFiles que representa todos os arquivos encontrados na pasta _PackageTempDir. A tarefa Copiar é então chamada, copiando todos esses arquivos para a pasta Destino de Publicação. O atributo DestinationFiles no elemento Copy é um pouco complexo; ele realiza uma transformação dos itens e converte seus caminhos em novos caminhos enraizados na pasta PublishDestination (verifique os metadados de itens conhecidos para ver o que esses% () s significam).

Para chamar este destino a partir da linha de comando, podemos agora simplesmente executar este comando (obviamente alterando o nome do arquivo de projeto e as propriedades de acordo com você):

msbuild Website.csproj "/p:Platform=AnyCPU;Configuration=Release;PublishDestination=F:\Temp\Publish" /t:PublishToFileSystem
P. Roe
fonte
3
Não consigo entender o trecho de código do novo destino (mostra 01 02 03 ...). Você poderia editar?
fan711,
2
Eu concordo com fan711. Porém, a solução é descrita no link - para que então copiá-la?
Антон Курьян
4
@ АнтонКурьян: Os links tendem a morrer depois de algum tempo, é por isso que as perguntas e respostas em stackoverflow.com devem ser sempre independentes, sem depender de recursos externos.
Oliver
Os resultados parecem que o perfil de publicação não está sendo usado pelo MSBuild e, em vez disso, está criando um pacote (talvez um padrão?). O que a solução abaixo faz para replicar o que o perfil está configurado para fazer, o que Microsoft.Web.Publishing.targets lida com a seleção do tipo correto de sua pasta de implantação (para FileSystem). Então, parece que você está reinventando a roda aqui, em vez de resolver esse problema. Mas não posso dizer com certeza sem o log do MSBuild. Eu coloquei o meu para trabalhar, detalhes na minha resposta
GregS
1
A solução de GregS não funciona para mim. Compila bem, mas nenhum arquivo é copiado para o diretório de publicação
rushinge
19

Ainda tive problemas depois de tentar todas as respostas acima (eu uso o Visual Studio 2013). Nada foi copiado para a pasta de publicação.

O problema é que se eu executar o MSBuild com um projeto individual em vez de uma solução, tenho que colocar um parâmetro adicional que especifica a versão do Visual Studio:

/p:VisualStudioVersion=12.0

12.0é para VS2013, substitua pela versão que você usa. Depois de adicionar esse parâmetro, ele simplesmente funcionou.

A linha de comando completa se parece com isto:

MSBuild C:\PathToMyProject\MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=MyPublishProfile /p:VisualStudioVersion=12.0

Eu encontrei aqui:

http://www.asp.net/mvc/overview/deployment/visual-studio-web-deployment/command-line-deployment

Eles afirmam:

Se você especificar um projeto individual em vez de uma solução, deverá adicionar um parâmetro que especifica a versão do Visual Studio.

felix-b
fonte
12

Parece-me que o seu perfil de publicação não está sendo usado e está executando um pacote padrão. Os destinos Microsoft Web Publish fazem tudo o que você está fazendo acima, ele seleciona os destinos corretos com base na configuração.

Consegui que o meu funcionasse sem problemas na etapa TeamCity MSBuild, mas especifiquei um caminho explícito para o perfil, basta chamá-lo pelo nome sem .pubxml (por exemplo, FileSystemDebug). Ele será encontrado contanto que esteja na pasta padrão, que é a sua.

Exemplo:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe ./ProjectRoot/MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=FileSystemDebug

Observe que isso foi feito usando as versões do Visual Studio 2012 dos destinos Microsoft Web Publish, normalmente localizados em "C: \ Arquivos de programas (x86) \ MSBuild \ Microsoft \ VisualStudio \ v11.0 \ Web". Verifique a pasta de implantação para os destinos de tipos de implantação específicos que são usados

GregS
fonte
A MS fez muitas melhorias desde que isso foi postado há alguns anos, obrigado pela programação atualizada?
P. Roe
3

Para sua informação: O mesmo problema com a execução em um servidor de compilação (Jenkins com msbuild 15 instalado, conduzido do VS 2017 em um projeto da web .NET Core 2.1).

No meu caso, foi o uso do destino "publicar" com msbuild que ignorou o perfil.

Então, meu comando msbuild começou com:

msbuild /t:restore;build;publish

Isso acionou corretamente o processo de publicação, mas nenhuma combinação ou variação de "/ p: PublishProfile = FolderProfile" funcionou para selecionar o perfil que eu queria usar ("FolderProfile").

Quando parei de usar o destino de publicação:

msbuild /t:restore;build /p:DeployOnBuild=true /p:PublishProfile=FolderProfile

Eu (tolamente) pensei que não faria diferença, mas assim que usei o switch DeployOnBuild ele pegou o perfil corretamente.

De Orbonia
fonte
3

Na verdade, juntei todas as suas respostas à minha própria solução de como resolver o problema acima:

  1. Eu crio o arquivo pubxml de acordo com minhas necessidades
  2. Em seguida, copio todos os parâmetros do arquivo pubxml para minha própria lista de parâmetros "/ p: foo = bar" para msbuild.exe
  3. Eu jogo fora o arquivo pubxml

O resultado é assim:

msbuild /t:restore /t:build /p:WebPublishMethod=FileSystem /p:publishUrl=C:\builds\MyProject\ /p:DeleteExistingFiles=True /p:LastUsedPlatform="Any CPU" /p:Configuration=Release

Rainer
fonte
1

Primeiro verifique a versão do Visual Studio do PC do desenvolvedor que pode publicar a solução (projeto). como mostrado é para VS 2013

 /p:VisualStudioVersion=12.0

adicione a linha de comando acima para especificar que tipo de versão do Visual Studio deve construir o projeto. Conforme as respostas anteriores, isso pode acontecer quando estamos tentando publicar apenas um projeto, não toda a solução.

Então, o código completo seria algo assim

"C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ msbuild.exe" "C: \ Arquivos de programas (x86) \ Jenkins \ workspace \ Jenkinssecondsample \ MVCSampleJenkins \ MVCSampleJenkins.csproj" / T: Build; Pacote / p : Configuração = DEBUG / p: OutputPath = "obj \ DEBUG" / p: DeployIisAppPath = "Site padrão / jenkinsdemoapp" /p:VisualStudioVersion=12.0

Shammie
fonte
1
Desculpe, shammakalubo, você interpretou mal a pergunta.
P. Roe
1
@shammakalubo A resposta está certa, mas não foi declarada completamente. Este parâmetro precisa ser adicionado ao comando mencionado pelo OP, que então se tornará: MSBuild C:\PathToMyProject\MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=MyPublishProfile /p:VisualStudioVersion=12.0Este parâmetro é o que estava faltando e resolvi meu problema. Você só precisa mencionar a resposta completamente!
Syed Waqas
@WaqasShah Obrigado, Como você mencionou, editei minha resposta e publiquei o código completo como ele seria.
Shammie