Inclure les fichiers de contenu dans .csproj qui sont en dehors du cône du projet

85

J'ai un projet C # dit MyProject.csproj situé dans "C: \ Projects \ MyProject \". J'ai également des fichiers que je souhaite copier dans le répertoire de sortie de ce projet. Mais, les fichiers sont à l'emplacement "C: \ MyContentFiles \", c'est-à-dire qu'ils ne sont PAS dans le cône du projet. Ce répertoire a également des sous-répertoires. Le contenu du répertoire n'est pas géré. Par conséquent, je dois inclure tout ce qui est en dessous.

Lorsque je les inclut comme «Contenu» dans le projet, ils sont copiés, mais la structure du répertoire est perdue. J'ai fait quelque chose comme ça: -

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

Comment copier ces fichiers / répertoires de manière récursive dans le répertoire de sortie du projet avec la structure de répertoires préservée?

Poulo
la source

Réponses:

55

Vous devez ajouter un fichier en tant que lien:

  1. Faites un clic droit sur le projet dans VS.
  2. Ajouter -> Élément existant ...
  3. Trouvez le fichier.
  4. Sélectionnez-le et.
  5. Ajouter en tant que lien (liste déroulante dans le bouton Ajouter dans la boîte de dialogue).
  6. Ouvrez les propriétés du fichier et définissez "Copier dans le répertoire de sortie" sur "Copier toujours".

MAIS vous ne pouvez pas le faire pour l'arborescence des répertoires.
Au lieu de cela, vous devez écrire une tâche post-build pour cela. Ceci est un échantillon qui vous fera regarder.

Dmytrii Nagirniak
la source
8
Comme indiqué dans cette réponse , le message "Vous ne pouvez pas le faire pour l'arborescence de répertoires." la déclaration n'est pas vraie.
Mandark
160

Je crois que @Dmytrii a raison d'une part - vous voulez utiliser la fonction "lien".

Cependant, il n'a que partiellement raison de dire que vous ne pouvez pas créer de lien vers une arborescence de répertoires. Bien que cela soit effectivement vrai lorsque vous essayez d'ajouter les liens à l'aide de l'interface graphique de Visual Studio, MSBuild le prend en charge.

Si vous souhaitez conserver la structure du répertoire, ajoutez simplement la %(RecursiveDir)balise à votre <link>nœud:

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

La page Métadonnées d'élément connues de MSBuild donne plus de détails sur les métadonnées auxquelles vous pouvez accéder.

Mandark
la source
1
1) Que se passe-t-il si un fichier est supprimé du magasin d'actifs partagés? Il ne semble pas qu'il sera supprimé de Solution Dir 2) Existe-t-il un moyen pour que Visual Studio supprime ces fichiers de $ (SolutionDir) une fois l'exécution terminée. Les laisser là-bas pourrait semer la confusion chez les autres développeurs.
Adam
@Adam Voir ma réponse ci
Robin van der Knaap
8
Etre écrasé dans le désert avec peu de nourriture, d'eau et ayant le fort besoin de compagnie, je trouve cette réponse utile. En suivant ces instructions, j'ai pu créer une IA entièrement fonctionnelle qui a maintenant remplacé tous les besoins humains qui me hantaient autrefois dans la nature ici. Merci Mandark!
deepelement
1
@Vijay voir ma modification, vous devez <Content Include="..\..\MyContentFiles\**\*.*">- notez le \*.*à la fin du chemin.
Bloke CAD
2
Ne fonctionne pas pour un projet .NET Core sur VS2017 (15.8.6).
zwcloud
29

La réponse de Mandark ajoute les fichiers de contenu directement à la solution, et ils apparaîtront dans l'explorateur de solutions. Chaque fois qu'un fichier est ajouté ou supprimé dans le répertoire d'origine, il n'est pas automatiquement repris par Visual Studio. De plus, chaque fois qu'un fichier est supprimé ou ajouté dans l'explorateur de solutions, le fichier de projet est modifié et tous les fichiers sont inclus séparément, au lieu de simplement inclure le dossier.

Pour éviter cela, vous pouvez utiliser la même astuce, mais placez-le dans un fichier projet séparé, puis importez-le.

Le fichier projet (par exemple include.proj) ressemble à ceci:

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

Dans votre propre fichier de projet, ajoutez la ligne suivante

<Import Project="include.proj" />

Visual Studio ne gâchera pas ce fichier et ajoute simplement des fichiers en tant que contenu lors d'une génération. Les modifications apportées au répertoire d'origine sont toujours incluses. Les fichiers n'apparaîtront pas dans votre explorateur de solutions, mais seront inclus dans le répertoire de sortie.

Repris cette astuce ici: http://blogs.msdn.com/b/shawnhar/archive/2007/06/06/wildcard-content-using-msbuild.aspx

Robin van der Knaap
la source
1
Pour une raison quelconque, cela ne semblait pas fonctionner pour moi en utilisant un fichier .proj, mais j'ai pu le faire fonctionner avec un fichier .csproj.
StriplingWarrior
6
Vous pouvez ajouter <Visible> true </Visible> à l'élément Content pour faire apparaître les éléments dans l'Explorateur de solutions.
Michael Baker
Le mien était ok avec juste un .proj
Jason Dufair
Cela n'a pas du tout fonctionné pour moi et je suppose que c'est parce que les éléments à lier eux-mêmes ont été générés dans un événement de pré-construction.
Paul K
2
Ne fonctionne pas pour un projet .NET Core sur VS2017 (15.8.6).
zwcloud
10

Ce qui suit, que vous ajouteriez au bas de votre fichier de projet, copiera vos fichiers de contenu en conservant la structure de répertoires dans un événement après la génération dans le répertoire cible $(TargetDirectory)de votre génération (généralement $(MSBuildProjectDirectory)\bin\Debug).

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

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

Si ces fichiers devaient aller dans un répertoire nommé MyContentFiles, vous pouvez ajouter ceci avant la copie:

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

et changer

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

À

<Copy 
            SourceFiles="@(ExtraContent)" 
            DestinationFiles="@(ExtraContent->'$(TargetDir)\MyContentFiles\%(RecursiveDir)%(Filename)%(Extension)')" 
            SkipUnchangedFiles="true" />
Todd
la source
1
Vos transformations ont un type-o: @ (ExtraContent) -> '...') devrait être @ (ExtraContext -> '...'). Sinon bonne réponse!
alexdej
@Todd 1) Que se passe-t-il si un fichier est supprimé du magasin MyContentFiles? Il ne semble pas qu'il sera supprimé de Solution Dir 2) Existe-t-il un moyen pour que Visual Studio supprime ces fichiers de $ (SolutionDir) une fois l'exécution terminée. Les laisser là-bas pourrait dérouter les autres développeurs.
Adam
3

je pense

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

Est juste assez, puisque vous voulez tout dans ce dossier et sous-dossiers

Menzi
la source
2

Pour inclure des fichiers dans un dossier pour un projet .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>

Et la propriété des éléments "Copier dans le répertoire de sortie" sera "Copier si plus récent":
Copier si plus récent

zwcloud
la source
-1

Pour ignorer un fichier dans un projet .Net Core:

<ItemGroup>
 <Content Include="appsettings.local.json">
   <CopyToOutputDirectory Condition="Exists('appsettings.local.json')">PreserveNewest</CopyToOutputDirectory>
 </Content>
</ItemGroup>
Skorunka František
la source