Gibt es eine Möglichkeit, Inhaltsdateien automatisch in die asp.net-Projektdatei aufzunehmen?

85

Ich füge meinem ASP.NET-Projekt häufig viele Inhaltsdateien (hauptsächlich Bilder und JS) hinzu. Ich verwende das VS-Veröffentlichungssystem. Beim Veröffentlichen werden neue Dateien erst veröffentlicht, wenn ich sie in das Projekt aufgenommen habe. Ich möchte alle Dateien automatisch in das angegebene Verzeichnis aufnehmen. Gibt es eine Möglichkeit anzugeben, welche Verzeichnisse automatisch in die csproj-Datei oder irgendwo anders aufgenommen werden sollen?

Marko
quelle
Siehe: Dies kann Ihnen helfen, stackoverflow.com/questions/1743432/…
Saar
1
nicht genau das, wonach ich suche
Marko
Ich habe meine Antwort bezüglich Ihres Problems aktualisiert, als ich den Ordner in Ihrem vs-Lösungsbrowser geändert habe.
Filburt

Antworten:

133

Alter Thread, ich weiß, aber ich habe einen Weg gefunden, dies zu tun, den ich immer wieder vergesse, und auf meiner Suche, ihn ein letztes Mal zu finden, bin ich auf diese Frage gestoßen. Der beste Weg, den ich gefunden habe, ist die Verwendung des BeforeBuild-Ziels in der .csproj-Datei.

<Target Name="BeforeBuild">
    <ItemGroup>
        <Content Include="**\*.less" />
    </ItemGroup>
</Target>

VS 2010 berührt diesen Abschnitt nicht und stellt sicher, dass Ihre Dateien bei jeder Erstellung des Projekts als Inhalt enthalten sind.

Chris
quelle
Was bedeutet .less? Und was bedeutet die ganze Saite **\*.less?
Registrierter Benutzer
3
.less-Dateien sind CSS-Dateien, die vom Less CSS-Präprozessor analysiert werden sollen. Google "Punkt weniger" für weitere Informationen dazu. Der Ausdruck **\*.lessbedeutet, dass alle * .less-Dateien in allen Verzeichnissen enthalten sind. In MSBUILD bedeutet ** "alle Verzeichnisse rekursiv"
Chris
4
Zumindest in VS 2012 wird dies leider auf die vollständige Liste erweitert, sobald Sie eine Datei zum Projekt hinzufügen / daraus entfernen und speichern. :(
Chris Phillips
3
Dies funktionierte für meine Situation erst, nachdem BeforeBuild in AfterBuild geändert wurde. Mein Build startet ein Powershell-Skript, mit dem Dateien verschoben werden, die dann von meinem Azure-Webbereitstellungsversuch nicht erfasst werden, da sie erst nach erfolgreichem Build vorhanden waren. Als ich "BeforeBuild" sah, wurde mir klar, dass es wahrscheinlich auch ein "AterBuild" gab. Hoffe das hilft jemand anderem.
Luke Rice
1
@ John siehe meine Antwort unten für eine Lösung für VS2015 +.
Jesse
54

Sie können einfach die .csproj-Datei Ihrer Website erweitern. Fügen Sie einfach Ihren Inhaltsstammordner mit einem rekursiven Platzhalter hinzu:

...
<ItemGroup>
    <!-- your normal project content -->
    <Content Include="Default.aspx" />

    <!-- your static content you like to publish -->
    <Content Include="Images\**\*.*" />
</ItemGroup>
...

Dadurch werden dieser Ordner und alle darunter liegenden Inhalte in Ihrem Lösungsbrowser sichtbar.

Wenn Sie versuchen, den Ordner im Lösungsbrowser durch Angabe auszublenden

<Content Include="Images\**.*.*">
    <Visible>false</Visible>
</Content>

es wird nicht veröffentlicht.


Aktualisieren

Wie Sie bereits festgestellt haben, wird der Platzhalter ersetzt, sobald Sie den Ordner in Ihrer Lösung berühren, da VS-Projekte nicht für beliebigen Inhalt ausgelegt sind.

Sie müssen also sicherstellen, dass der Ordner und sein Inhalt niemals innerhalb von VS geändert werden. Das Hinzufügen oder Entfernen von Dateien kann nur im Dateisystem erfolgen. Genau das wollten Sie, da ich Ihre Frage verstanden habe.

Es wäre einfacher, wenn der Ordner in VS ausgeblendet werden könnte, aber ich konnte keinen Weg finden, ihn auszublenden UND zu veröffentlichen.

Ein anderer erfolgloser Ansatz bestand darin, den Ordner durch eine CreateItemAufgabe einzuschließen. Dies führte dazu, dass der Inhalt des Ordners in \ bin \ app.publish \ ... veröffentlicht wurde und nicht davon überzeugt werden konnte, ihn zusammen mit den Inhaltselementen in der .csproj zu veröffentlichen, sodass ich ihn in meiner Antwort nicht präsentierte.

Filburt
quelle
3
Es funktioniert so lange, bis ich eine Datei manuell hinzufüge oder entferne. Nach dieser Zeile verschwindet <Content Include = "Images * *. " /> Aus der Projektdatei.
Marko
2
@ Marko ist richtig. Nach dem Hinzufügen hat <Content Include="Images\**\*.*" />es funktioniert. Sobald Sie weitere Bilder hinzugefügt haben, wird die .csproj-Datei geändert und alle Dateien in den Bildern / ... wieder aufgelistet. <Content Include = "Images * *. " /> Ist nicht mehr vorhanden .
Ravi Ram
Stecken Sie diesen Code in eine separate .proj-Datei und rufen Sie ihn vom Ziel vor dem Erstellen in der .csproj-Datei auf.
NL - Entschuldigen Sie sich bei Monica
20

Für diejenigen, die Probleme mit der Antwort von Chris haben , ist dies die Lösung für Visual Studio 2012 und höher:

<Target Name="ContentsBeforeBuild" AfterTargets="BeforeBuild">
  <ItemGroup>
    <Content Include="images\**" />
  </ItemGroup>
</Target>

Wie Chris in seiner Antwort erwähnt hat, wird Visual Studio diesen Abschnitt nicht berühren <Target>, selbst wenn Sie manuell mit dem Zielverzeichnis herumspielen (Hinzufügen / Entfernen von Dateien).

Bitte beachten Sie, dass Sie sollten ein Unterverzeichnis enthalten , in dem sich die Dateien befinden (im Fall oben, es ist images). Visual Studio / MSBuild platziert diese Dateien in demselben Verzeichnis innerhalb der Projektstruktur. Wenn Sie kein Unterverzeichnis verwenden, werden die Dateien im Stammverzeichnis der Projektstruktur abgelegt.

Für eine kurze Erklärung der Platzhalter:

  • **bedeutet alles rekursiv (Dateien, Unterverzeichnisse und Dateien innerhalb dieser)
  • *.extEnthält alle Dateien mit der Erweiterung extim Verzeichnis der obersten Ebene, jedoch keine Unterverzeichnisse
    • Zum Beispiel *.extkönnte sein *.png, *.jsusw. Jede wird Dateierweiterung arbeiten
  • **\*.extEnthält alle Dateien mit der Erweiterung extaus dem Verzeichnis der obersten Ebene und alle Unterverzeichnisse.
  • Siehe die Antwort von Wie verwende ich Nant / Ant-Namensmuster? für eine vollständigere Erklärung mit Beispielen.

Beachten Sie zum Abschluss, dass es einen Unterschied zwischen der Verwendung <Target>und der Nichtverwendung gibt.

Mit dem <Target>Ansatz, Visual Studio wird nicht zeigen , die Dateien innerhalb des Solution Explorer.

<Target Name="ContentsBeforeBuild" AfterTargets="BeforeBuild">
  <ItemGroup>
    <Content Include="images\**" />
  </ItemGroup>
</Target>

Der nicht <Target>Ansatz wird Visual Studio anweisen, zeigt die Dateien innerhalb des Solution Explorer. Der Nachteil bei diesem ist, dass jede Manipulation der automatischen Verzeichnisse dazu führt, dass Visual Studio den Platzhaltereintrag überschreibt. Es sollte auch beachtet werden , dass der Ansatz unten wird nur die Lösung Explorer aktualisieren , auf die Lösung / Projekt in VS. Öffnung Selbst die Symbolleistenschaltfläche "Aktualisieren" des Projektmappen-Explorers reicht nicht aus.

<ItemGroup>
  <Content Include="images\**" />
</ItemGroup>
Jesse
quelle
1
Vielen Dank, dass Sie experimentiert und auf die Unterschiede zwischen der Verwendung von <Ziel> und nicht hingewiesen haben. Tolle Erklärung der Details der Platzhalter.
Kurt Hutchinson
@ KurtHutchinson - kein Problem. =)
Jesse
Ich glaube, diese Lösung muss poliert werden. Wenn Sie target anweisen, nach "BeforeBuild" auszuführen, kann dies theoretisch auch NACH der Veröffentlichung geschehen. Die aktuelle Lösung funktioniert wahrscheinlich aus Glück.
Imre Pühvel
@ ImrePühvel Wie wird die Veröffentlichung vor der BeforeBuildVeranstaltung durchgeführt? MSBuild muss zuerst das Projekt und die Binärdateien erstellen, bevor überhaupt eine Veröffentlichung in Betracht gezogen werden kann.
Jesse
1
Ich habe nicht behauptet, dass die Veröffentlichung vor dem Erstellen erfolgen soll, aber dass die Deklaration nicht garantiert, dass die Elemente vor der Veröffentlichung zum Inhalt hinzugefügt werden. Aus dem Codebeispiel : .. AfterTargets="BeforeBuild". Das heißt, Ihr benutzerdefiniertes Ziel muss nach BeforeBuild ausgeführt werden, es wird jedoch nicht angegeben, wie viel danach. Mein Fehler ist jedoch, dass der aktuelle Zielbestellungsalgorithmus in Ordnung sein sollte: msdn.microsoft.com/en-us/library/ee216359.aspx
Imre Pühvel
10

Sie können die System.IO.Directory.GetFile(string)Methode des Frameworks und seine Überladungen verwenden, um alle Dateien rekursiv einzuschließen.

  <ItemGroup>
    <Content Include="$([System.IO.Directory]::GetFiles('$(ProjectDir)Scripts\', '*.js', SearchOption.AllDirectories))" />
    <Content Include="$([System.IO.Directory]::GetFiles('$(ProjectDir)Images\', '*.png', SearchOption.AllDirectories))" />
  </ItemGroup>
Steven Liekens
quelle
Das war eine große Hilfe für mich; Ich habe mehrere Verzeichnisse, einige Ebenen tief und viele Dateien, die ich automatisch einschließen wollte, und dies machte all diese Inhalte zu einem. Vielen Dank!
Jay Otterbein
2
Ich habe noch mehr damit experimentiert und es stellt sich heraus, dass dies dieselben Einschränkungen aufweist wie Include="**\*.ext"bei Platzhaltern.
Steven Liekens
Wow, enthält die Projektdatei Run Powershell? Ist das überhaupt Sandkasten? Das ist ein Exploit, der darauf wartet, passiert zu werden.
Brain2000
Es ist nicht PowerShell. MSBuild verfügt über eine eigene Syntax zum Aufrufen statischer Methoden. Laut docs ist dies auf Systemklassen beschränkt. docs.microsoft.com/en-us/visualstudio/msbuild/… Obwohl ich sicher bin, dass Sie nur <Exec> Powershell mit irgendwelchen Argumenten können ...
Steven Liekens
3

Ich habe geschrieben, wie ich die Inhalts-Includes mit einem kleinen Powershell-Skript erstellen konnte:

$folders = Get-ChildItem .\ -r -Directory
$filtered = $folders |Select-Object @{Name='FullName';Expression={$_.fullname.replace($pwd,'')}}, @{Name='FolderDepth';Expression={($_.fullname.Split('\').Count) - ($Pwd.Path.split('\').count)}} | Sort-Object -Descending FullName,folderDepth 
$basefolders = $filtered | Where-Object{$_.folderdepth -eq 1}
$basefoldersobj = @()
foreach($basefolder in $basefolders)
{
  $basefoldername =$baseFolder.fullname
  $filteredbase = $filtered -match "\$basefoldername\\" | Sort-Object -Descending FolderDepth | Select-Object -first 1
  if($filteredbase -eq $null)
  {
    $filteredbase = $filtered -match "\$basefoldername" | Sort-Object -Descending FolderDepth | Select-Object -first 1
  }
  $obj = New-Object psobject
  Add-Member -InputObject $obj -MemberType NoteProperty -Name 'Folder' -Value $basefolder.fullname.trim('\')
  Add-member -InputObject $obj -MemberType NoteProperty -Name 'DeepestPath' -Value $filteredbase.folderDepth
  $basefoldersobj += $obj
}
$include = '*.*'
foreach($bfolderObj in $basefoldersobj)
{
  $includecount = ''
  $includecount = "\$include" * ($bfolderObj.Deepestpath)
  Write-Output "<content Include=`"$($bfolderObj.folder)$includecount`" /> "
}

Dies sollte die erforderliche include-Anweisung an der Powershell-Eingabeaufforderung erzeugen

thom schumacher
quelle
2

Sie können Dateien mit solchen Links hinzufügen. Sie können durchsucht und angezeigt werden. Sie werden jedoch nicht ausgecheckt, wenn Sie versuchen, sie zu ändern. Außerdem lässt Visual Studio die Platzhalter an Ort und Stelle:

  <ItemGroup>
    <Content Include="..\Database Schema\Views\*.sql">
      <Link>Views\*.sql</Link>
    </Content>
  </ItemGroup>

Dies geht in die .proj-Datei.

chongo2002
quelle
1
Ich habe dies versucht und VS ersetzt den Platzhalter durch die einzelnen Dateien, wenn ich eine Datei mit VS hinzufüge oder entferne.
carlin.scott
Dies ist sehr elegant, aber Sie sollten den Platzhalter vom Link-Ziel entfernen
SimSimY
1

Meines Wissens nicht; Mein Vorschlag ist jedoch, sie in das Projekt einzufügen, da sie standardmäßig enthalten sind. Verwenden Sie Visual Studio, um die Dateien in die Ordner einzufügen, anstatt sie über den Explorer in das Verzeichnis einzufügen.

Kamranicus
quelle
-1

Ich erkannte, dass die beste Lösung dafür darin besteht, Dateien einzeln manuell hinzuzufügen. Wenn Sie Hunderte von ihnen haben, wie ich, war es nur eine Frage von wenigen Stunden. Komisch, dass dieses ernste Problem auch 2016 mit VS 2015 noch nicht gelöst ist. Ahh, wie ich Xcode liebe.

Marcin Skoczylas
quelle