Incluindo arquivos de conteúdo em .csproj que estão fora do cone do projeto


86

Eu tenho um projeto C # que diz MyProject.csproj localizado em "C: \ Projects \ MyProject \". Também tenho arquivos que desejo copiados para o diretório de saída deste projeto. Porém, os arquivos estão na localização "C: \ MyContentFiles \", ou seja, NÃO estão dentro do cone do projeto. Este diretório também possui subdiretórios. O conteúdo do diretório não é gerenciado. Portanto, tenho que incluir tudo o que está sob ele.

Quando eu os incluo como 'Conteúdo' no projeto, eles são copiados, mas a estrutura do diretório é perdida. Eu fiz algo assim: -

<Content Include="..\..\MyContentFiles\**">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

Como copio esses arquivos / diretórios recursivamente no diretório de saída do projeto com a estrutura de diretório preservada?

Respostas:


56

Você precisa adicionar o arquivo como um link:

  1. Clique com o botão direito no projeto no VS.
  2. Adicionar -> Item Existente ...
  3. Encontre o arquivo.
  4. Selecione-o e.
  5. Adicionar como um link (menu suspenso no botão Adicionar na caixa de diálogo).
  6. Abra as propriedades do arquivo e defina "Copiar para diretório de saída" como "Copiar sempre".

MAS você não pode fazer isso para a árvore de diretórios.
Em vez disso, você precisa escrever uma tarefa de pós-construção para isso. Este é um exemplo que o deixará surpreso.


8
Conforme declarado nesta resposta , o "Você não pode fazer isso para a árvore de diretórios." declaração não é verdade.
Mandark

164

Eu acredito que @Dmytrii acertou por um lado - você quer usar o recurso "link".

No entanto, ele está apenas parcialmente correto ao dizer que você não pode vincular a uma árvore de diretório. Embora isso seja, de fato, verdadeiro ao tentar adicionar os links usando a GUI do Visual Studio, o MSBuild oferece suporte para isso.

Se você deseja preservar a estrutura do diretório, basta adicionar a %(RecursiveDir)tag ao seu <link>nó:

<Content Include="..\..\MyContentFiles\**\*.*">
  <Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

A página Metadados de item conhecidos do MSBuild apresenta mais detalhes sobre os metadados que você pode acessar.


1
1) O que acontece se um arquivo for excluído do armazenamento de ativos compartilhados? Parece que não será excluído do Solution Dir 2) Existe alguma maneira de fazer o Visual Studio excluir esses arquivos de $ (SolutionDir) após a conclusão da execução. Deixá-los lá pode confundir outros desenvolvedores.
Adam

@Adam Veja minha resposta abaixo
Robin van der Knaap

9
Tendo caído no deserto com pouca comida e água e tendo uma forte necessidade de companhia, acho esta resposta útil. Seguindo essas instruções, fui capaz de construir uma IA totalmente funcional que agora substituiu todas as necessidades humanas que antes me assombravam no deserto aqui. Obrigado Mandark!
deepelement

1
@Vijay veja minha edição, você precisa <Content Include="..\..\MyContentFiles\**\*.*">- observe o \*.*no final do caminho.
CAD cara

3
Não funciona para um projeto .NET Core no VS2017 (15.8.6).
zwcloud

29

A resposta do Mandark adiciona os arquivos de conteúdo diretamente à solução e eles aparecerão no gerenciador de soluções. Sempre que um arquivo é adicionado ou excluído do diretório original, ele não é selecionado pelo Visual Studio automaticamente. Além disso, sempre que um arquivo é excluído ou adicionado ao explorador de soluções, o arquivo do projeto é alterado e todos os arquivos são incluídos separadamente, em vez de apenas incluir a pasta.

Para evitar isso, você pode usar o mesmo truque, mas colocá-lo em um arquivo de projeto separado e importá-lo.

O arquivo do projeto (por exemplo, include.proj) tem a seguinte aparência:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Content Include="..\..\MyContentFiles\**">
  <Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

Em seu próprio arquivo de projeto, adicione a seguinte linha

<Import Project="include.proj" />

O Visual Studio não vai mexer com esse arquivo e apenas adiciona arquivos como conteúdo durante uma compilação. As alterações no diretório original são sempre incluídas. Os arquivos não aparecerão em seu explorador de soluções, mas serão incluídos no diretório de saída.

Aprendeu esse truque aqui: http://blogs.msdn.com/b/shawnhar/archive/2007/06/06/wildcard-content-using-msbuild.aspx


1
Por algum motivo, isso não pareceu funcionar para mim usando um arquivo .proj, mas consegui fazê-lo funcionar com um arquivo .csproj.
StriplingWarrior

6
Você pode adicionar <Visible> true </Visible> ao elemento Content para fazer os itens aparecerem no Solution Explorer.
Michael Baker

O meu estava ok com apenas um .proj
Jason Dufair

Isso não funcionou para mim de forma alguma e estou assumindo que é porque os próprios itens a serem vinculados foram gerados em um evento pré-compilado.
Paul K

2
Não funciona para um projeto .NET Core no VS2017 (15.8.6).
zwcloud

11

O seguinte, que você adicionaria ao final de seu arquivo de projeto, copiará seus arquivos de conteúdo mantendo a estrutura de diretório em um evento após a compilação para o diretório $(TargetDirectory)de destino de sua compilação (normalmente $(MSBuildProjectDirectory)\bin\Debug).

<ItemGroup>
    <ExtraContent Include="$(MSBuildProjectDirectory)\..\..\MyContentFiles\**" />
</ItemGroup>

<Target Name="AfterBuild">
    <Copy 
        SourceFiles="@(ExtraContent)" 
        DestinationFiles="@(ExtraContent->'$(TargetDir)\%(RecursiveDir)%(Filename)%(Extension)')" 
        SkipUnchangedFiles="true" />
</Target>

Se esses arquivos precisassem ir para um diretório chamado MyContentFiles, você poderia adicionar isso antes da cópia:

<MakeDir Directories="$(TargetDir)\MyContentFiles" Condition=" !Exists('$(TargetDir\MyContentFiles') " />

e mudar

<Copy 
            SourceFiles="@(ExtraContent)" 
            DestinationFiles="@(ExtraContent->'$(TargetDir)\%(RecursiveDir)%(Filename)%(Extension)')" 
            SkipUnchangedFiles="true" />

Para

<Copy 
            SourceFiles="@(ExtraContent)" 
            DestinationFiles="@(ExtraContent->'$(TargetDir)\MyContentFiles\%(RecursiveDir)%(Filename)%(Extension)')" 
            SkipUnchangedFiles="true" />

1
Suas transformações têm um tipo-o: @ (ExtraContent) -> '...') deve ser @ (ExtraContext -> '...'). Caso contrário, boa resposta!
alexdej

@Todd 1) O que acontece se um arquivo for excluído do armazenamento MyContentFiles? Parece que não será excluído do Solution Dir 2) Existe alguma maneira de fazer o Visual Studio excluir esses arquivos de $ (SolutionDir) após a conclusão da execução. Deixá-los lá pode confundir outros desenvolvedores.
Adam

Era disso que eu precisava. O projeto e o processo de construção agora estão funcionando conforme o esperado, mas os arquivos não são publicados com um clique uma vez no aplicativo. Alguma dica para isso?
Georg W.

4

eu acho que

<Content Include="..\..\MyContentFiles\**\*.*">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

É apenas o suficiente, já que você quer tudo nessa pasta e subpastas


2

Para incluir arquivos em uma pasta para um projeto .NET Core,

<!--Just files-->
<ItemGroup>
  <None Update="..\..\MyContentFiles\**\*.*">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>
<!--Content files-->
<ItemGroup>
  <Content Include="..\..\MyContentFiles\**\*.*" Link="MyContentFiles\%(RecursiveDir)%(Filename)%(Extension)">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </Content>
</ItemGroup>

E a propriedade dos itens "Copiar para diretório de saída" será "Copiar se mais recente":
Copiar se for mais recente


-1

Para ignorar um arquivo em um projeto .Net Core:

<ItemGroup>
 <Content Include="appsettings.local.json">
   <CopyToOutputDirectory Condition="Exists('appsettings.local.json')">PreserveNewest</CopyToOutputDirectory>
 </Content>
</ItemGroup>
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.