Existe uma maneira de incluir automaticamente arquivos de conteúdo no arquivo de projeto asp.net?

86

Freqüentemente, estou adicionando muitos arquivos de conteúdo (principalmente imagens e js) ao meu projeto ASP.NET. Estou usando o sistema de publicação VS e, ao publicar, novos arquivos não são publicados até que eu os inclua no projeto. Eu gostaria de incluir automaticamente todos os arquivos no diretório especificado. Existe uma maneira de especificar quais diretórios devem ser incluídos automaticamente no arquivo csproj ou em qualquer outro lugar?

Marko
fonte
veja: isso pode ajudá-lo a stackoverflow.com/questions/1743432/…
Saar,
1
Não exatamente o que eu estou procurando
Marko
Atualizei minha resposta em relação ao seu problema ao modificar a pasta dentro do navegador da solução vs.
Filburt

Respostas:

134

Tópico antigo, eu sei, mas encontrei uma maneira de fazer isso que continuo esquecendo e, em minha busca para encontrá-la pela última vez, tropecei nessa questão. A melhor maneira que descobri para fazer isso é usar o destino BeforeBuild no arquivo .csproj.

<Target Name="BeforeBuild">
    <ItemGroup>
        <Content Include="**\*.less" />
    </ItemGroup>
</Target>

O VS 2010 não tocará nesta seção e garante que seus arquivos sejam incluídos como conteúdo sempre que o projeto for construído.

Chris
fonte
Qual é o significado de .less? E o que significa toda a corda **\*.less?
Usuário registrado em
3
Arquivos .less são arquivos css destinados a serem analisados ​​pelo pré-processador Less CSS. Google "ponto a menos" para obter mais informações sobre isso. A expressão **\*.lesssignifica incluir todos os arquivos * .less em todos os diretórios. Em linguagem MSBUILD, ** significa 'todos os diretórios recursivamente'
Chris
4
Pelo menos no VS 2012, assim que você adiciona / remove um arquivo do projeto e salva, isso infelizmente é expandido para a lista completa. :(
Chris Phillips
3
Isso funcionou para a minha situação apenas depois de alterar BeforeBuild para AfterBuild, meu build inicia um script PowerShell que move arquivos, que então não seriam captados por minha tentativa de implantação do azure web porque eles só existiam depois que o build fosse bem-sucedido. Ver "BeforeBuild" me mostrou que provavelmente havia um "AterBuild" também. Espero que isso ajude mais alguém.
Luke Rice,
1
@John veja minha resposta abaixo para uma correção para VS2015 +.
Jesse
54

Você simplesmente pode estender o arquivo .csproj do seu site. Basta adicionar sua pasta raiz de conteúdo com um caractere curinga recursivo:

...
<ItemGroup>
    <!-- your normal project content -->
    <Content Include="Default.aspx" />

    <!-- your static content you like to publish -->
    <Content Include="Images\**\*.*" />
</ItemGroup>
...

Isso torna esta pasta e todo o conteúdo abaixo visíveis dentro do navegador da solução.

Se você tentar ocultar a pasta dentro do navegador da solução, especificando

<Content Include="Images\**.*.*">
    <Visible>false</Visible>
</Content>

não será publicado.


Atualizar

Como você já descobriu, o curinga será substituído assim que você tocar na pasta dentro de sua solução porque os projetos do VS não são projetados para conter conteúdo arbitrário.

Portanto, você terá que garantir que a pasta e seu conteúdo nunca sejam modificados de dentro do VS - adicionar ou remover arquivos só pode ser feito no sistema de arquivos ... que é o que você queria, pois entendi sua pergunta.

Seria mais fácil se a pasta pudesse estar oculta no VS, mas não consegui encontrar uma maneira de ocultá-la E publicar.

Outra abordagem malsucedida foi incluir a pasta por uma CreateItemTarefa. Isso resultou na publicação do conteúdo da pasta em \ bin \ app.publish \ ... e não pude ser convencido a publicá-lo junto com os itens de conteúdo dentro do .csproj, então não o apresentei em minha resposta.

Filburt
fonte
3
Funciona até eu adicionar ou remover o arquivo manualmente. Depois dessa linha, <Content Include = "Images * *. " /> Desaparece do arquivo de projeto.
Marko
2
@Marko está correto. Depois de adicionar <Content Include="Images\**\*.*" />funcionou. Depois de adicionar mais imagens, o .csproj é alterado e volta a listar todos os arquivos nas imagens / ... e <Content Include = "Images * *. " /> Desaparece.
Ravi Ram
Cole esse código em um arquivo .proj separado e chame-o do destino antes da compilação no arquivo .csproj.
NL - Peça desculpas a Monica,
21

Para aqueles que têm problemas para usar a resposta de Chris , esta é a solução para o Visual Studio 2012 e mais recente:

<Target Name="ContentsBeforeBuild" AfterTargets="BeforeBuild">
  <ItemGroup>
    <Content Include="images\**" />
  </ItemGroup>
</Target>

Como Chris mencionou em sua resposta - o Visual Studio não tocará nesta <Target>seção, mesmo se você mexer manualmente (adicionando / removendo arquivos) com o diretório de destino.

Observe que você deve incluir um subdiretório onde os arquivos estão localizados (no caso acima, é images). O Visual Studio / MSBuild colocará esses arquivos no mesmo diretório dentro da estrutura do projeto. Se você não usar um subdiretório, os arquivos serão colocados na raiz da estrutura do projeto.

Para uma explicação rápida dos curingas:

  • **significa tudo recursivamente (arquivos, subdiretórios e arquivos dentro deles)
  • *.extirá incluir todos os arquivos com extensão extdentro do diretório de nível superior, mas não subdiretórios
    • Por exemplo, *.extpoderia ser *.png, *.jsetc. Qualquer extensão de arquivo irá funcionar
  • **\*.extincluirá todos os arquivos com extensão extdo diretório de nível superior e todos os subdiretórios.
  • Veja a resposta em Como uso os padrões de nomenclatura Nant / Ant? para uma explicação mais completa com exemplos.

Para completar, observe que há uma diferença entre usá-lo <Target>e não usá-lo.

Com a <Target>abordagem, o Visual Studio não mostrará os arquivos no Solution Explorer.

<Target Name="ContentsBeforeBuild" AfterTargets="BeforeBuild">
  <ItemGroup>
    <Content Include="images\**" />
  </ItemGroup>
</Target>

A não <Target>abordagem irá instruir o Visual Studio para mostrar os arquivos dentro do Solution Explorer. A desvantagem desse aqui é que qualquer manipulação dos diretórios automáticos fará com que o Visual Studio substitua a entrada curinga. Também deve ser observado que a abordagem abaixo atualizará o Gerenciador de Soluções ao abrir a Solução / Projeto no VS. Mesmo o botão "atualizar" da barra de ferramentas do Solution Explorer não fará isso.

<ItemGroup>
  <Content Include="images\**" />
</ItemGroup>
Jesse
fonte
1
Obrigado por experimentar e apontar as diferenças entre usar <Target> e não. Ótima explicação dos detalhes dos curingas também.
Kurt Hutchinson
@KurtHutchinson - sem problemas. =)
Jesse
Eu acredito que essa solução precisa de polimento. Quando você instrui o destino a ser executado após "BeforeBuild", em teoria isso também pode acontecer APÓS a publicação. A solução atual provavelmente funciona devido à sorte.
Imre Pühvel
@ ImrePühvel como você acha que a publicação acontece antes do BeforeBuildevento? O MSBuild deve primeiro criar o projeto e os binários antes mesmo de considerar a publicação.
Jesse
1
Não afirmei que a publicação acontecesse antes da construção, mas que a declaração não garante que os itens sejam adicionados ao conteúdo antes da publicação. Da amostra de código: .. AfterTargets="BeforeBuild". Ou seja, seu destino personalizado deve ser executado após BeforeBuild, mas não especifica quanto depois. Porém, erro meu, pelo algoritmo de ordenação de destino atual, deve estar tudo bem: msdn.microsoft.com/en-us/library/ee216359.aspx
Imre Pühvel
10

Você pode usar o System.IO.Directory.GetFile(string)método do framework e suas sobrecargas para incluir recursivamente todos os arquivos.

  <ItemGroup>
    <Content Include="$([System.IO.Directory]::GetFiles('$(ProjectDir)Scripts\', '*.js', SearchOption.AllDirectories))" />
    <Content Include="$([System.IO.Directory]::GetFiles('$(ProjectDir)Images\', '*.png', SearchOption.AllDirectories))" />
  </ItemGroup>
Steven Liekens
fonte
Isso foi uma grande ajuda para mim; Eu tenho vários diretórios com alguns níveis de profundidade e muitos arquivos que queria incluir automaticamente e isso transformou todos esses conteúdos em um. Obrigado!
Jay Otterbein
2
Experimentei mais um pouco e descobri que tem as mesmas limitações dos Include="**\*.ext"curingas.
Steven Liekens,
Uau, o arquivo de projeto inclui a execução do PowerShell? Isso é sandbox? É uma façanha esperando para acontecer.
Brain2000
Não é PowerShell. MSBuild tem sua própria sintaxe para invocar métodos estáticos. De acordo com os documentos, isso é limitado a classes do sistema. docs.microsoft.com/en-us/visualstudio/msbuild/… Embora eu tenha certeza que você pode apenas <Exec> powershell com qualquer argumento ...
Steven Liekens
3

Eu escrevi como consegui incluir o conteúdo criado com um pequeno script PowerShell:

$folders = Get-ChildItem .\ -r -Directory
$filtered = $folders |Select-Object @{Name='FullName';Expression={$_.fullname.replace($pwd,'')}}, @{Name='FolderDepth';Expression={($_.fullname.Split('\').Count) - ($Pwd.Path.split('\').count)}} | Sort-Object -Descending FullName,folderDepth 
$basefolders = $filtered | Where-Object{$_.folderdepth -eq 1}
$basefoldersobj = @()
foreach($basefolder in $basefolders)
{
  $basefoldername =$baseFolder.fullname
  $filteredbase = $filtered -match "\$basefoldername\\" | Sort-Object -Descending FolderDepth | Select-Object -first 1
  if($filteredbase -eq $null)
  {
    $filteredbase = $filtered -match "\$basefoldername" | Sort-Object -Descending FolderDepth | Select-Object -first 1
  }
  $obj = New-Object psobject
  Add-Member -InputObject $obj -MemberType NoteProperty -Name 'Folder' -Value $basefolder.fullname.trim('\')
  Add-member -InputObject $obj -MemberType NoteProperty -Name 'DeepestPath' -Value $filteredbase.folderDepth
  $basefoldersobj += $obj
}
$include = '*.*'
foreach($bfolderObj in $basefoldersobj)
{
  $includecount = ''
  $includecount = "\$include" * ($bfolderObj.Deepestpath)
  Write-Output "<content Include=`"$($bfolderObj.folder)$includecount`" /> "
}

Isso deve produzir a instrução include necessária no prompt do PowerShell

Thom Schumacher
fonte
2

Você pode adicionar arquivos com links como este, eles podem ser pesquisados, visualizados, mas não são finalizados se você tentar alterá-los. Além disso, o Visual Studio mantém os curingas no lugar:

  <ItemGroup>
    <Content Include="..\Database Schema\Views\*.sql">
      <Link>Views\*.sql</Link>
    </Content>
  </ItemGroup>

Isso vai dentro do arquivo .proj.

chongo2002
fonte
1
Tentei fazer isso e o VS substitui o curinga pelos arquivos individuais quando adiciono ou removo um arquivo usando o VS.
carlin.scott
Isso é muito elegante, mas você deve remover o caractere curinga do destino do link
SimSimY
1

Não que eu saiba; no entanto, minha sugestão é colá-los no projeto, pois isso os incluirá por padrão. Portanto, em vez de colá-los no diretório por meio do Explorer, use o Visual Studio para colar os arquivos nas pastas.

Kamranicus
fonte
-1

Percebi que a melhor solução para isso é adicionar arquivos manualmente, um por um. Se você tem centenas deles como eu, era questão de apenas algumas horas. Engraçado que mesmo em 2016 com o VS 2015 esse sério problema ainda não foi resolvido. Ahh, como eu amo o Xcode.

Marcin Skoczylas
fonte