Einfügen von Inhaltsdateien in .csproj, die sich außerhalb des Projektkegels befinden

84

Ich habe ein C # -Projekt namens MyProject.csproj unter "C: \ Projects \ MyProject \". Ich habe auch Dateien, die ich in das Ausgabeverzeichnis dieses Projekts kopieren möchte. Die Dateien befinden sich jedoch am Speicherort "C: \ MyContentFiles \", dh sie befinden sich NICHT im Projektkegel. Dieses Verzeichnis hat auch Unterverzeichnisse. Der Inhalt des Verzeichnisses wird nicht verwaltet. Daher muss ich alles einbeziehen, was darunter steht.

Wenn ich sie als 'Inhalt' in das Projekt einbinde, werden sie kopiert, aber die Verzeichnisstruktur geht verloren. Ich habe so etwas gemacht: -

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

Wie kopiere ich diese Dateien / Verzeichnisse rekursiv in das Ausgabeverzeichnis des Projekts, wobei die Verzeichnisstruktur erhalten bleibt?

Poulo
quelle

Antworten:

53

Sie müssen eine Datei als Link hinzufügen:

  1. Klicken Sie mit der rechten Maustaste auf das Projekt in VS.
  2. Hinzufügen -> Vorhandenes Element ...
  3. Suchen Sie die Datei.
  4. Wählen Sie es aus und.
  5. Fügen Sie als Link (Drop - Down in der Schaltfläche Hinzufügen im Dialog).
  6. Öffnen Sie die Eigenschaften der Datei und setzen Sie "In Ausgabeverzeichnis kopieren" auf "Immer kopieren".

ABER Sie können es nicht für den Verzeichnisbaum tun.
Stattdessen müssen Sie dafür eine Post-Build-Aufgabe schreiben. Dies ist ein Beispiel , das Sie starren lässt.

Dmytrii Nagirniak
quelle
8
Wie in dieser Antwort angegeben , wird "Sie können dies nicht für den Verzeichnisbaum tun". Aussage ist nicht wahr.
Mandark
160

Ich glaube, @Dmytrii macht es einerseits richtig - Sie möchten die "Link" -Funktion verwenden.

Er hat jedoch nur teilweise Recht, wenn er sagt, dass Sie keine Verknüpfung zu einem Verzeichnisbaum herstellen können. Während dies tatsächlich der Fall ist, wenn versucht wird, die Links über die GUI von Visual Studio hinzuzufügen, unterstützt MSBuild dies.

Wenn Sie die Verzeichnisstruktur beibehalten möchten, fügen Sie einfach das %(RecursiveDir)Tag zu Ihrem <link>Knoten hinzu:

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

Auf der Seite MSBuild Bekannte Elementmetadaten werden die Metadaten, auf die Sie zugreifen können, ausführlicher beschrieben.

Mandark
quelle
1
1) Was passiert, wenn eine Datei aus dem Shared Assets Store gelöscht wird? Es sieht nicht so aus, als würde es aus dem Solution Dir gelöscht. 2) Gibt es eine Möglichkeit, Visual Studio dazu zu bringen, diese Dateien nach Abschluss des Laufs aus $ (SolutionDir) zu löschen? Wenn Sie sie dort lassen, können andere Entwickler verwirrt werden.
Adam
@ Adam Siehe meine Antwort unten
Robin van der Knaap
7
Ich finde diese Antwort hilfreich, wenn ich in der Wildnis mit wenig Nahrung, Wasser und dem starken Bedürfnis nach Kameradschaft zusammengebrochen bin. Durch Befolgen dieser Anweisungen konnte ich eine voll funktionsfähige KI aufbauen, die jetzt alle menschlichen Bedürfnisse ersetzt hat, die mich einst in der Wildnis hier heimgesucht haben. Danke Mandark!
deepelement
1
@ Vijay siehe meine Bearbeitung, die Sie benötigen <Content Include="..\..\MyContentFiles\**\*.*">- beachten Sie die \*.*am Ende des Pfades.
CAD Kerl
2
Funktioniert nicht für ein .NET Core-Projekt unter VS2017 (15.8.6).
Zwcloud
29

Die Antwort von Mandark fügt die Inhaltsdateien direkt zur Lösung hinzu und sie werden im Lösungs-Explorer angezeigt . Wenn eine Datei im ursprünglichen Verzeichnis hinzugefügt oder gelöscht wird, wird diese von Visual Studio nicht automatisch übernommen. Wenn eine Datei im Lösungs-Explorer gelöscht oder hinzugefügt wird, wird die Projektdatei geändert, und alle Dateien werden separat eingeschlossen, anstatt nur den Ordner einzuschließen.

Um dies zu verhindern, können Sie denselben Trick verwenden, ihn jedoch in eine separate Projektdatei einfügen und anschließend importieren.

Die Projektdatei (zum Beispiel include.proj) sieht folgendermaßen aus:

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

Fügen Sie in Ihrer eigenen Projektdatei die folgende Zeile hinzu

<Import Project="include.proj" />

Visual Studio wird mit dieser Datei nicht herumspielen und fügt während eines Builds nur Dateien als Inhalt hinzu. Änderungen im ursprünglichen Verzeichnis sind immer enthalten. Die Dateien werden nicht in Ihrem Lösungs-Explorer angezeigt, sondern in das Ausgabeverzeichnis aufgenommen.

Ich habe diesen Trick hier aufgegriffen: http://blogs.msdn.com/b/shawnhar/archive/2007/06/06/wildcard-content-using-msbuild.aspx

Robin van der Knaap
quelle
1
Aus irgendeinem Grund schien dies bei Verwendung einer .proj-Datei nicht zu funktionieren, aber ich konnte es mit einer .csproj-Datei zum Laufen bringen.
StriplingWarrior
6
Sie können dem Inhaltselement <Visible> true </ Visible> hinzufügen, damit die Elemente im Projektmappen-Explorer angezeigt werden.
Michael Baker
Meins war in Ordnung mit nur einem .proj
Jason Dufair
Dies hat bei mir überhaupt nicht funktioniert und ich gehe davon aus, dass die zu verknüpfenden Elemente selbst in einem Pre-Build-Ereignis generiert wurden.
Paul K
2
Funktioniert nicht für ein .NET Core-Projekt unter VS2017 (15.8.6).
Zwcloud
10

Das Folgende, das Sie am Ende Ihrer Projektdatei hinzufügen würden, kopiert Ihre Inhaltsdateien unter Beibehaltung der Verzeichnisstruktur in einem After-Build-Ereignis in das Zielverzeichnis $(TargetDirectory)Ihres Builds (normalerweise $(MSBuildProjectDirectory)\bin\Debug).

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

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

Wenn diese Dateien in ein Verzeichnis mit dem Namen MyContentFiles verschoben werden müssen, können Sie dies vor der Kopie hinzufügen:

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

und ändern

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

Zu

<Copy 
            SourceFiles="@(ExtraContent)" 
            DestinationFiles="@(ExtraContent->'$(TargetDir)\MyContentFiles\%(RecursiveDir)%(Filename)%(Extension)')" 
            SkipUnchangedFiles="true" />
Todd
quelle
1
Ihre Transformationen haben den Typ-o: @ (ExtraContent) -> '...') sollte @ (ExtraContext -> '...') sein. Ansonsten gute Antwort!
Alexdej
@Todd 1) Was passiert, wenn eine Datei aus dem MyContentFiles-Speicher gelöscht wird? Es sieht nicht so aus, als würde es aus dem Solution Dir gelöscht. 2) Gibt es eine Möglichkeit, Visual Studio dazu zu bringen, diese Dateien nach Abschluss des Laufs aus $ (SolutionDir) zu löschen? Wenn Sie sie dort lassen, können andere Entwickler verwirrt werden.
Adam
3

Meiner Ansicht nach

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

Ist gerade genug, da Sie alles in diesem Ordner und Unterordnern wollen

Menzi
quelle
2

So fügen Sie Dateien in einen Ordner für ein .NET Core-Projekt ein:

<!--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>

Die Eigenschaft "In Ausgabeverzeichnis kopieren" der Elemente lautet "Bei neuerer Version kopieren":
Kopieren, wenn neuer

zwcloud
quelle
-1

So ignorieren Sie eine Datei in einem .NET Core-Projekt:

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