.NET – Dateien nach dem Build in ein bestimmtes Verzeichnis kopieren

 C Programming >> C-Programmierung >  >> Tags >> .NET
.NET – Dateien nach dem Build in ein bestimmtes Verzeichnis kopieren

Die einfachste Methode zum Kopieren von Dateien nach dem Build in einem .NET-Projekt ist die Verwendung des MSBuild-Kopiertasks in der CSPROJ-Datei wie folgt:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <Target Name="CopyDLLs" AfterTargets="Build">
    <Message Text="Executing CopyDLLs task" Importance="High" />

    <Copy
      SourceFiles="$(TargetDir)$(ProjectName).dll;$(TargetDir)$(ProjectName).pdb"
      DestinationFolder="C:\Builds$(ProjectName)" />

    <Message Text="Copied build files" Importance="High" />
  </Target>

</Project>
Code language: HTML, XML (xml)

Hinweis:Ich verwende VS2019.

Mein Projekt heißt NotesAPI. Wenn ich baue, protokolliert es die folgenden Meldungen:

1>------ Build started: Project: NotesAPI, Configuration: Debug Any CPU ------
1>NotesAPI -> C:\NotesAPI\bin\Debug\netcoreapp3.1\NotesAPI.dll
1>Executing CopyDLLs task
1>Copied build files
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========Code language: plaintext (plaintext)

Es kopierte die folgenden Build-Dateien in C:\Build\NotesAPI:

  • NotesAPI.dll
  • NotesAPI.pdb

In diesem Artikel erkläre ich die im obigen Beispiel verwendete Copy Task-Syntax. Dann zeige ich, wie man einen Zeitstempel in den Verzeichnisnamen einfügt, und schließlich zeige ich, wie man das kopierte Verzeichnis komprimiert.

Aufschlüsselung der Kopieraufgabensyntax

Bisher haben Sie Build-Dateien so kopiert, dass Sie Befehlszeilenargumente in ein Post-Build-Ereignis eingefügt haben. Jetzt haben wir die Kopieraufgabe, die die Dinge etwas einfacher macht, sobald Sie die Syntax gelernt haben.

Werfen wir einen Blick auf die Syntax des Kopierauftrags, indem wir sie von Grund auf neu schreiben.

Fügen Sie das Target-Element hinzu

Zuerst brauchen wir ein Target-Element, das die Kopieraufgabe enthält:

<Target Name="CopyDLLs" AfterTargets="Build">

</Target>
Code language: HTML, XML (xml)

Dieses Ziel hat zwei Eigenschaften:

  • Name:Ein eindeutiger Name für das Ziel. Mein einziger Rat hier ist, sicherzustellen, dass der Name beschreibend ist.
  • AfterTargets=“Build“:Da wir die Build-Dateien kopieren wollen, müssen wir das nach dem Build tun, daher AfterTargets=“Build“.

Die CopyDLLs Target wird ausgeführt, nachdem das Projekt erstellt wurde.

Fügen Sie die Kopieraufgabe hinzu

Wenn Sie eine Kopieraufgabe hinzufügen, müssen Sie mindestens angeben, welche Dateien kopiert werden sollen und wohin sie kopiert werden sollen, wie hier:

<Target Name="CopyDLLs" AfterTargets="Build">

	<Copy
	  SourceFiles="$(TargetDir)$(ProjectName).dll;$(TargetDir)$(ProjectName).pdb"
	  DestinationFolder="C:\Builds$(ProjectName)" />

</Target>

Code language: HTML, XML (xml)

Diese Kopieraufgabe gibt zwei Eigenschaften an:

  • Quelldateien:Eine oder mehrere Dateien (durch Semikolon getrennt). Sie können auch das Platzhalterzeichen (*) verwenden.
  • DestinationFolder:Wohin die Dateien kopiert werden sollen.

Diese beiden Eigenschaften verwenden MSBuild-Makros (anstelle von hartcodierten Werten):

  • $(TargetDir):Das Build-Ausgabeverzeichnis. Beispiel:C:\NotesAPI\bin\Debug\netcoreapp3.1\
  • $(ProjectName):Der Name der Projektdatei. Beispiel:NotesAPI.

Nachrichtenaufgaben hinzufügen, um zu protokollieren, was während des Builds passiert

Message Tasks sind im Grunde wie Log-Meldungen im Build-Prozess. Sie erleichtern die Fehlerbehebung.

So fügen Sie dem enthaltenden Ziel Nachrichtenaufgaben hinzu:

<Target Name="CopyDLLs" AfterTargets="Build">
	<Message Text="Executing CopyDLLs task" Importance="High" />

	<Copy
	  SourceFiles="$(TargetDir)$(ProjectName).dll;$(TargetDir)$(ProjectName).pdb"
	  DestinationFolder="C:\Builds$(ProjectName)" />

	<Message Text="Copied build files" Importance="High" />
</Target>
Code language: HTML, XML (xml)

Nehmen wir an, es gibt ein Problem während der Kopieraufgabe. Der Message Task protokolliert „Executing CopyDLLs task“ direkt vor der Fehlermeldung, was uns hilft, sofort zu erkennen, dass das Problem in den CopyDLLs aufgetreten ist Aufgabe:

1>------ Build started: Project: NotesAPI, Configuration: Debug Any CPU ------
1>NotesAPI -> C:\NotesAPI\bin\Debug\netcoreapp3.1\NotesAPI.dll
1>Executing CopyDLLs task
1>C:\NotesAPI\NotesAPI.csproj(10,5): error MSB3030: Could not copy the file "\NotesAPI.dll" because it was not found.
1>Done building project "NotesAPI.csproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Code language: plaintext (plaintext)

Den Zielverzeichnisnamen mit einem Zeitstempel versehen

Angenommen, Sie möchten jedes Mal, wenn der Build ausgeführt wird, Dateien in ein Verzeichnis mit einem Zeitstempel im Namen kopieren.

So versehen Sie das Zielverzeichnis einer Kopieraufgabe mit einem Zeitstempel:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <Target Name="CopyDLLs" AfterTargets="Build">
    <Message Text="Executing CopyDLLs task" Importance="High" />
    
    <PropertyGroup>
      <CopyToDir>C:\Builds$(ProjectName)_$([System.DateTime]::UtcNow.ToString(yyyy-MM-ddThhmmss))_$(Configuration)</CopyToDir>
    </PropertyGroup>
    
    <Copy
      SourceFiles="$(TargetDir)$(ProjectName).dll;$(TargetDir)$(ProjectName).pdb"
      DestinationFolder="$(CopyToDir)" />

    <Message Text="Copied build files to $(CopyToDir)" Importance="High" />
  </Target>

</Project>
Code language: HTML, XML (xml)

Das Ausführen des Builds gibt Folgendes aus:

1>------ Rebuild All started: Project: NotesAPI, Configuration: Debug Any CPU ------
1>NotesAPI -> C:\NotesAPI\bin\Debug\netcoreapp3.1\NotesAPI.dll
1>Executing CopyDLLs task
1>Copied build files to C:\Builds\NotesAPI_2021-05-20T121046_Debug
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========Code language: plaintext (plaintext)

Es hat das Verzeichnis C:\Builds\NotesAPI_2021-05-20T121046_Debug erstellt.

Lassen Sie uns die hier involvierte Syntax aufschlüsseln, indem wir sie von Grund auf neu schreiben.

Fügen Sie das PropertyGroup-Element hinzu

Stellen Sie sich Eigenschaften wie Variablen im Code vor. Sie können Ihr eigenes hinzufügen und es beliebig benennen und dann an anderen Stellen im Code darauf verweisen.

Wenn Sie Ihre eigene Eigenschaft hinzufügen, muss sie in einem PropertyGroup-Element enthalten sein. Fügen Sie also ein PropertyGroup-Element und eine neue Eigenschaft namens CopyToDir hinzu :

<Target Name="CopyDLLs" AfterTargets="Build">
	<Message Text="Executing CopyDLLs task" Importance="High" />

	<PropertyGroup>
	  <CopyToDir></CopyToDir>
	</PropertyGroup>

	<Copy
	  SourceFiles="$(TargetDir)$(ProjectName).dll;$(TargetDir)$(ProjectName).pdb"
	  DestinationFolder="C:\Builds$(ProjectName)" />

	<Message Text="Copied build files" Importance="High" />
</Target>
Code language: HTML, XML (xml)

Verzeichnisnamen mit Zeitstempel berechnen

Jetzt haben wir die Eigenschaft und müssen einen Wert dafür angeben. In diesem Fall möchten wir ein Verzeichnis mit Zeitstempel angeben.

So geht's:

<PropertyGroup>
  <CopyToDir>C:\Builds$(ProjectName)_$([System.DateTime]::UtcNow.ToString(yyyy-MM-ddThhmmss))_$(Configuration)</CopyToDir>
</PropertyGroup>
Code language: HTML, XML (xml)

Das sieht nach einer sehr komplizierten Zeichenfolge aus. Es verwendet eine Kombination aus Zeichenfolgenliteralen, MSBuild-Makros und ruft sogar eine Methode auf.

Lassen Sie es uns aufschlüsseln.

  • MSBuild-Makros:

C:\Builds\$(Projektname) _$([System.DateTime]::UtcNow.ToString(yyyy-MM-ddThhmmss))_$(Configuration)

$(ProjectName) wird in den Namen des Projekts aufgelöst. In diesem Fall lautet der Projektname NotesAPI .

$(Configuration) wird in die Build-Konfiguration aufgelöst. In diesem Fall habe ich einen Debug-Build erstellt, also wird dies zu Debug. aufgelöst

  • Aufruf einer Methode:

C:\Builds\$(ProjectName)_$([System.DateTime]::UtcNow.ToString(yyyy-MM-ddThhmmss)) _$(Konfiguration)

Dies entspricht dem Aufruf von:

System.DateTime.UtcNow.ToString("yyyy-MM-ddThhmmss")
Code language: C# (cs)

Gibt die aktuelle Datumszeit aus, z. B.:2021-05-20T121046 .

Zusammengenommen ergibt sich der Eigenschaftswert dynamisch zu:C:\Builds\NotesAPI_2021-05-20T121046_Debug .

Beziehen Sie sich auf die Eigenschaft in den Kopier- und Nachrichtenaufgaben

Nun zum wichtigsten Teil – der Nutzung der Immobilie. So verwenden Sie CopyToDir Wert der Eigenschaft, verwenden Sie $(CopyToDir) wie folgt:

<Target Name="CopyDLLs" AfterTargets="Build">
	<Message Text="Executing CopyDLLs task" Importance="High" />

	<PropertyGroup>
	  <CopyToDir>C:\Builds$(ProjectName)_$([System.DateTime]::UtcNow.ToString(yyyy-MM-ddThhmmss))_$(Configuration)</CopyToDir>
	</PropertyGroup>

	<Copy
	  SourceFiles="$(TargetDir)$(ProjectName).dll;$(TargetDir)$(ProjectName).pdb"
	  DestinationFolder="$(CopyToDir)" />

	<Message Text="Copied build files to $(CopyToDir)" Importance="High" />
</Target>
Code language: HTML, XML (xml)

Wenn die Aufgaben ausgeführt werden, wird $(CopyToDir) durch seinen dynamischen Wert ersetzt (z. B.:C:\Builds\NotesAPI_2021-05-20T121046_Debug ).

Zielverzeichnis komprimieren

Nehmen wir an, nachdem Sie die Dateien kopiert haben, möchten Sie das Zielverzeichnis komprimieren. Sie können den ZipDirectory-Task wie folgt verwenden:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <Target Name="CopyDLLs" AfterTargets="Build">
    <Message Text="Executing CopyDLLs task" Importance="High" />

    <PropertyGroup>
      <CopyToDir>C:\Builds$(ProjectName)_$([System.DateTime]::UtcNow.ToString(yyyy-MM-ddThhmmss))_$(Configuration)</CopyToDir>
    </PropertyGroup>

    <Copy
      SourceFiles="$(TargetDir)$(ProjectName).dll;$(TargetDir)$(ProjectName).pdb"
      DestinationFolder="$(CopyToDir)" />

    <Message Text="Copied build files to $(CopyToDir). Now zipping it up." Importance="High" />

    <ZipDirectory SourceDirectory="$(CopyToDir)" DestinationFile="$(CopyToDir).zip" />

    <Message Text="CopyDLLs task completed" Importance="High" />
  </Target>

</Project>
Code language: HTML, XML (xml)

Das Ausführen des Builds gibt Folgendes aus:

1>------ Rebuild All started: Project: NotesAPI, Configuration: Debug Any CPU ------
1>NotesAPI -> C:\NotesAPI\bin\Debug\netcoreapp3.1\NotesAPI.dll
1>Executing CopyDLLs task
1>Copied build files to C:\Builds\NotesAPI_2021-05-21T120836_Debug. Now zipping it up.
1>Zipping directory "C:\Builds\NotesAPI_2021-05-21T120836_Debug" to "C:\Builds\NotesAPI_2021-05-21T120836_Debug.zip".
1>CopyDLLs task completed
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

Code language: plaintext (plaintext)

Hinweis:Der ZipDirectory-Task selbst gibt diese freundliche Nachricht aus und erklärt genau, was er gezippt hat und wo er die gezippte Datei abgelegt hat.

Die ZipDirectory Task-Syntax ist relativ einfach:

  • SourceDirectory:Was zu komprimieren.
  • DestinationFile:Wo soll die ZIP-Datei abgelegt werden.

Beachten Sie, dass sich diese beiden Eigenschaften auf CopyToDir beziehen Eigentum. Dieselbe Eigenschaft wurde in der Kopieraufgabe verwendet. Es ist eine gute Idee, Ihre eigene Eigenschaft wie diese zu verwenden, anstatt doppelte Werte fest zu codieren.

ZipDirectory schlägt fehl, wenn der Verzeichnisname einen Zeilenumbruch enthält

Wenn Sie Ihre eigenen Eigenschaften definieren, lassen Sie die Werte in einer einzigen Zeile. Andernfalls schlägt ZipDirectory mit folgendem Fehler fehl:

Dieser Fehler würde beispielsweise auftreten, wenn Sie CopyToDir definiert haben Eigenschaft wie diese:

<PropertyGroup>
  <CopyToDir>
	C:\Builds$(ProjectName)_$([System.DateTime]::UtcNow.ToString(yyyy-MM-ddThhmmss))_$(Configuration)
  </CopyToDir>
</PropertyGroup>
Code language: HTML, XML (xml)

Beachten Sie, dass sich der in der Eigenschaft definierte Wert tatsächlich in einem Zeilenumbruch befindet. Dieser Zeilenumbruch ist Teil der Zeichenfolge und ZipDirectory kann damit nicht umgehen.

Setzen Sie den Eigenschaftswert stattdessen immer in eine einzelne Zeile, etwa so:

<PropertyGroup>
  <CopyToDir>C:\Builds$(ProjectName)_$([System.DateTime]::UtcNow.ToString(yyyy-MM-ddThhmmss))_$(Configuration)</CopyToDir>
</PropertyGroup>
Code language: HTML, XML (xml)