Copie os arquivos para o diretório de saída usando csproj dotnetcore

96

Portanto, meu problema é muito simples. Eu tenho alguns arquivos que quero ser copiados para o diretório de saída da compilação, seja uma compilação de depuração ou uma publicação de lançamento. Todas as informações que posso encontrar são sobre a antiga abordagem de configuração json. Alguém tem um exemplo usando o csproj com dotnetcore?

Eles são
fonte

Respostas:

133

Existem várias maneiras de atingir seus objetivos, dependendo de quais são suas necessidades.

A abordagem mais fácil é definir os itens de metadados ( CopyToOutputDirectory/ CopyToPublishDirectory) condicionalmente (assumindo .txtser um Noneitem em vez de Content, se não funcionar, tente <Content>):

<ItemGroup Condition="'$(Configuration)' == 'Debug'">
  <None Update="foo.txt" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

Se mais controle for necessário, a abordagem mais versátil é adicionar destinos personalizados que se conectam ao processo de compilação no arquivo csproj:

<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
  <Copy SourceFiles="foo.txt" DestinationFolder="$(OutDir)" />
</Target>
<Target Name="CopyCustomContentOnPublish" AfterTargets="Publish">
  <Copy SourceFiles="foo.txt" DestinationFolder="$(PublishDir)" />
</Target>

Isso copia um arquivo para os respectivos diretórios. Para mais opções para a <Copy>tarefa, consulte sua documentação . Para limitar isso a certas configurações, você pode usar um Conditionatributo:

<Target  Condition=" '$(Configuration)' == 'Release' ">

Este Conditionatributo pode ser aplicado tanto no <Target>elemento quanto em elementos de tarefa como <Copy>.

Martin Ullrich
fonte
Como eu aplicaria 'DestinationFolder' aos itens <Reference>, ou se é possível, não há muito nos documentos que eu possa encontrar. Não quero todos os meus assemblies no nível raiz e preferiria que estivessem em suas próprias pastas.
Reahreic
Você pode definir DestinationSubDirectory="subdir\"metadados em Referenceitens diretamente. No entanto, isso significa que você mesmo precisa implementar a resolução de montagem ( evento AssemblyResolve )
Martin Ullrich
Como posso copiar a pasta pai que contém algumas dlls nas respectivas pastas. Quero disponibilizá-los no caminho publicado de saída para que, depois de criar essas pastas, fiquem disponíveis para meu aplicativo em tempo de execução, conforme carrego essas dlls como plug-ins na inicialização. Estou usando o rider no mac
kuldeep
89

Embora isso tenha me ajudado a resolver o problema, não funcionou para todos os arquivos em um subdiretório. Eu também usei em Content Includevez de Content Update;

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="layouts\*.*">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>  
  </ItemGroup>

</Project>
Sr. Moose
fonte
3
Todas as outras permutações de todas as outras respostas / sugestões não funcionaram para mim. Nem mesmo uma menção ao arquivo na saída detalhada da compilação. Mas sua sugestão aqui funcionou.
user7817808
15
E se você quiser incluir subpastas intermediárias, use<Content Include="layouts\**\*.*">
JSancho
3
Ao usar o Web SDK ( <Project Sdk="Microsoft.NET.Sdk.Web">), ele não permitirá que você use, Include=porque já parece especificar isso implicitamente no SDK. Eu tive que usar Update=para obtê-lo para construir e incluir meus arquivos adicionais.
notracs
Legal, obrigado .. Mas como copiar apenas o conteúdo da pasta para o diretório de saída e não a própria pasta. A expressão assets\*.*deve assumi-lo. Mas ele copia a pasta de ativos completa. Então, eu tenho, bin/Debug/netcoreapp3.1/assets/...mas quero os arquivos da pasta de ativos no diretório raiz da saída. bin/Debug/netcoreapp3.1/....
Dominik
Eu encontrei uma solução: xml <Project Sdk="Microsoft.NET.Sdk"> <ItemGroup> <AssetsSourceFiles Include="assets/**/*.*"/> </ItemGroup> <Target Name="CopyCustomContent" AfterTargets="AfterBuild"> <Copy SourceFiles="@(AssetsSourceFiles)" DestinationFolder="$(OutDir)" SkipUnchangedFiles="true" /> </Target> </Project> (veja minha resposta para um formato de código melhor.)
Dominik
15

Coloque-o no arquivo .csproj substituindo nlog.config pelo caminho de arquivo desejado. Em seguida, basta salvá-lo e construir seu projeto:

<ItemGroup>
  <Content Update="Nlog.config">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Content>
</ItemGroup>
Chad Kuehn
fonte
Isso não parece copiar subdiretórios.
nulo
9

Supondo que você tenha uma assetspasta em seu diretório raiz. Você pode nomeá-lo como quiser. Este é apenas um exemplo:

your-project.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <ItemGroup>
    <AssetsSourceFiles Include="assets/**/*.*"/>
  </ItemGroup>

  <Target Name="CopyCustomContent" AfterTargets="AfterBuild">
    <Copy SourceFiles="@(AssetsSourceFiles)" DestinationFolder="$(OutDir)" SkipUnchangedFiles="true" />
  </Target>
</Project>

isso copia apenas o conteúdo da assetspasta para a raiz de saída sem envolvê-lo na assetspasta. Mas se quiser copiar com a própria pasta, você pode usar o seguinte código:

<Project Sdk="Microsoft.NET.Sdk">
  <ItemGroup>
    <Content Include="assets\**\*.*">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
</Project>
Dominik
fonte
3

Tive a necessidade de uma seleção de modelos HTML para serem consumíveis tanto no lado do cliente quanto no lado do servidor (Handlebars js)

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Content Update="wwwroot\html-templates\**\*.*">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

</Project>
hngr18
fonte
0

Obrigado, você salva o meu dia, se você precisar forçar a cópia de um pacote nuget específico em um projeto principal asp.net (2.2), adicione no final de seu csproj:

<!-- Force copy MathNet because we need it in compilation -->
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="Build">
    <PropertyGroup>
        <ErrorText>This project references NuGet package(s) that are missing on this computer. The missing file is {0}.</ErrorText>
    </PropertyGroup>
    <Error Condition="!Exists('..\packages\MathNet.Numerics.4.8.1\lib\netstandard2.0\MathNet.Numerics.dll')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MathNet.Numerics.4.8.1\lib\netstandard2.0\MathNet.Numerics.dll'))" />
</Target>

<ItemGroup>
    <ContentWithTargetPath Include="..\packages\MathNet.Numerics.4.8.1\lib\netstandard2.0\MathNet.Numerics.dll">
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <TargetPath>MathNet.Numerics.dll</TargetPath>
    </ContentWithTargetPath>
</ItemGroup>
Gab89
fonte
0
<PropertyGroup>
    <PostBuildEvent>xcopy "$(ProjectDir)Xml" "$(ProjectDir)$(OutDir)Xml" /S /F /I /R /Y</PostBuildEvent>
</PropertyGroup>

ou

<PropertyGroup>
    <PostBuildEvent>copy /Y "$(ProjectDir)MyXml.xml" "$(ProjectDir)$(OutDir)Xml"</PostBuildEvent>
</PropertyGroup>
isxaker
fonte
O ideal é usar uma tarefa <Copy> para torná-la multiplataforma.
Bruno Garcia