Existe-t-il un moyen d'inclure automatiquement les fichiers de contenu dans le fichier de projet asp.net?

86

J'ajoute fréquemment beaucoup de fichiers de contenu (principalement des images et des js) à mon projet ASP.NET. J'utilise le système de publication VS et lors de la publication, les nouveaux fichiers ne sont pas publiés tant que je ne les ai pas inclus dans le projet. Je voudrais inclure automatiquement tous les fichiers dans le répertoire spécifié. Existe-t-il un moyen de spécifier quels répertoires doivent être automatiquement inclus dans le fichier csproj ou ailleurs?

Marko
la source
voir: cela peut vous aider stackoverflow.com/questions/1743432/…
Sarre
1
pas exactement ce que je recherche
Marko
J'ai mis à jour ma réponse concernant votre problème lors de la modification du dossier dans votre navigateur vs solution.
Filburt

Réponses:

134

Vieux fil, je sais, mais j'ai trouvé un moyen de faire cela que je n'arrête pas d'oublier, et dans ma recherche pour le retrouver une dernière fois, je suis tombé sur cette question. Le meilleur moyen que j'ai trouvé pour cela est d'utiliser la cible BeforeBuild dans le fichier .csproj.

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

VS 2010 ne touchera pas à cette section et garantit que vos fichiers sont inclus en tant que contenu à chaque fois que le projet est créé.

Chris
la source
Quelle est la signification de .less? Et que signifie toute la chaîne **\*.less?
Utilisateur enregistré
3
Les fichiers .less sont des fichiers css destinés à être analysés par le préprocesseur Less CSS. Google "dot less" pour plus d'informations à ce sujet. L'expression **\*.lesssignifie inclure tous les fichiers * .less dans tous les répertoires. Dans MSBUILD, ** signifie `` tous les répertoires de manière récursive ''
Chris
4
Au moins dans VS 2012, dès que vous ajoutez / supprimez un fichier du projet et enregistrez-le, cela est malheureusement étendu à la liste complète. :(
Chris Phillips
3
Cela n'a fonctionné pour ma situation qu'après avoir changé BeforeBuild en AfterBuild, ma compilation lance un script PowerShell qui déplace les fichiers, qui ne seraient alors pas récupérés par ma tentative de déploiement azure web car ils n'existaient qu'après la réussite de la construction. Voir "BeforeBuild" m'a fait comprendre qu'il y avait probablement aussi un "AterBuild". J'espère que ceci aide quelqu'un d'autre.
Luke Rice le
1
@John voir ma réponse ci-dessous pour un correctif à VS2015 +.
Jesse
54

Vous pouvez simplement étendre le fichier .csproj de votre site Web. Ajoutez simplement votre dossier racine de contenu avec un caractère générique récursif:

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

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

Cela rend ce dossier et tout le contenu ci-dessous visibles dans votre navigateur de solution.

Si vous essayez de masquer le dossier dans le navigateur de solution en spécifiant

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

il ne sera pas publié.


Mise à jour

Comme vous l'avez déjà découvert, le caractère générique sera remplacé dès que vous toucherez le dossier à l'intérieur de votre solution car les projets VS ne sont pas conçus pour contenir un contenu arbitraire.

Vous devrez donc vous assurer que le dossier et son contenu ne sont jamais modifiés à partir de VS - l'ajout ou la suppression de fichiers ne peut être fait que sur le système de fichiers ... c'est ce que vous vouliez après avoir compris votre question.

Ce serait plus facile si le dossier pouvait être caché dans VS mais je ne pouvais pas trouver un moyen de le cacher ET de le publier.

Une autre approche infructueuse consistait à inclure le dossier par une CreateItemtâche. Cela a abouti à la publication du contenu du dossier dans \ bin \ app.publish \ ... et je n'ai pas pu être convaincu de le publier avec les éléments de contenu à l'intérieur du .csproj, donc je ne l'ai pas présenté dans ma réponse.

Filburt
la source
3
Cela fonctionne jusqu'à ce que j'ajoute ou supprime le fichier manuellement. Après cette ligne, <Content Include = "Images * *. " /> Disparaît du fichier de projet.
Marko
2
@Marko a raison. Après avoir ajouté <Content Include="Images\**\*.*" />cela a fonctionné. Une fois que vous avez ajouté d'autres images, le .csproj est modifié et revient à la liste de tous les fichiers dans les images / ... et le <Content Include = "Images * *. " /> Est parti.
Ravi Ram
Collez ce code dans un fichier .proj séparé et appelez-le à partir de la cible de construction précédente dans le fichier .csproj.
NL - Présentez vos excuses à Monica
21

Pour ceux qui rencontrent des problèmes avec la réponse de Chris, voici la solution pour Visual Studio 2012 et plus récent:

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

Comme Chris l'a mentionné dans sa réponse - Visual Studio n'y touchera pas<Target> section, même si vous manipulez manuellement (ajout / suppression de fichiers) avec le répertoire cible.

S'il vous plaît noter que vous devez inclure un sous - répertoire où se trouvent les fichiers (dans le cas ci - dessus, il est images). Visual Studio / MSBuild placera ces fichiers dans le même répertoire dans la structure du projet. Si vous n'utilisez pas de sous-répertoire, les fichiers seront placés à la racine de la structure du projet.

Pour une explication rapide des caractères génériques:

  • **signifie tout récursivement (fichiers, sous-répertoires et fichiers dans ceux-ci)
  • *.extinclura tous les fichiers avec l'extension extdans le répertoire de niveau supérieur, mais pas les sous-répertoires
    • Par exemple, *.extpourrait être *.png,*.js etc. Toute extension de fichier ne fonctionnera
  • **\*.extinclura tous les fichiers avec l'extension extdu répertoire de niveau supérieur et tous les sous-répertoires.
  • Voir la réponse dans Comment utiliser les modèles de dénomination Nant / Ant?pour une explication plus complète avec des exemples.

Pour terminer, veuillez noter qu'il existe une différence entre l'utiliser <Target>et ne pas l'utiliser.

Avec l' <Target>approche, Visual Studio n'affichera pas les fichiers dans l'Explorateur de solutions.

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

La non - <Target>approche va donner des instructions Visual Studio pour afficher les fichiers dans la solution Explorer. L'inconvénient de celui-ci est que toute manipulation des répertoires automatiques entraînera le remplacement de l'entrée générique par Visual Studio. Il convient également de noter que l'approche ci-dessous ne mettra à jour l'Explorateur de solutions qu'à l'ouverture de la solution / projet dans VS. Même le bouton "Actualiser" de la barre d'outils de l'Explorateur de solutions ne le fera pas.

<ItemGroup>
  <Content Include="images\**" />
</ItemGroup>
Jesse
la source
1
Merci d'avoir expérimenté et souligné les différences entre l'utilisation de <Target> et non. Excellente explication des détails des jokers aussi.
Kurt Hutchinson
@KurtHutchinson - pas de problème. =)
Jesse
Je pense que cette solution doit être peaufinée. Lorsque vous demandez à la cible de s'exécuter après "BeforeBuild", cela peut également arriver en théorie APRÈS la publication. La solution actuelle fonctionne probablement grâce à la chance.
Imre Pühvel
@ ImrePühvel comment pensez-vous que la publication se déroule avant l' BeforeBuildévénement? MSBuild doit d'abord générer le projet et les binaires avant même d'envisager la publication.
Jesse
1
Je n'ai pas prétendu que la publication avait lieu avant la construction, mais que la déclaration ne garantit pas que les éléments sont ajoutés au contenu avant la publication. A partir de l' exemple de code: .. AfterTargets="BeforeBuild". Cela signifie que votre cible personnalisée doit s'exécuter après BeforeBuild, mais elle ne spécifie pas combien après. Cependant, mon erreur, selon l'algorithme de commande des cibles actuel, cela devrait être correct: msdn.microsoft.com/en-us/library/ee216359.aspx
Imre Pühvel
10

Vous pouvez utiliser la System.IO.Directory.GetFile(string)méthode du framework et ses surcharges pour inclure récursivement tous les fichiers.

  <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
la source
Cela m'a beaucoup aidé; J'ai plusieurs répertoires de quelques niveaux de profondeur et beaucoup de fichiers que je voulais inclure automatiquement et cela a transformé tous ces contenus en un seul. Merci!
Jay Otterbein
2
J'ai expérimenté cela un peu plus et il s'avère que cela a les mêmes limites Include="**\*.ext"qu'avec les jokers.
Steven Liekens
Wow, est-ce que le fichier de projet inclut run PowerShell? Est-ce que ce bac à sable est du tout? C'est un exploit qui attend.
Brain2000
Ce n'est pas PowerShell. MSBuild a sa propre syntaxe pour appeler des méthodes statiques. Selon la documentation, cela est limité à des classes système. docs.microsoft.com/en-us/visualstudio/msbuild/ ... Bien que je sois sûr que vous pouvez simplement <Exec> powershell avec tous les arguments ...
Steven Liekens
3

J'ai écrit comment j'ai pu obtenir le contenu créé avec un petit script PowerShell:

$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`" /> "
}

Cela devrait produire l'instruction include nécessaire à l'invite PowerShell

Thom Schumacher
la source
2

Vous pouvez ajouter des fichiers avec des liens comme celui-ci, ils sont consultables, consultables, mais ils ne sont pas récupérés si vous essayez de les modifier.Visual studio laisse également les caractères génériques en place:

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

Cela va dans le fichier .proj.

chongo2002
la source
1
J'ai essayé cela et VS remplace le caractère générique par les fichiers individuels lorsque j'ajoute ou supprime un fichier à l'aide de VS.
carlin.scott
C'est très élégant, mais vous devriez supprimer le caractère générique de la cible du lien
SimSimY
1

Pas à ma connaissance; cependant ma suggestion est de les coller dans le projet car cela les inclura par défaut. Ainsi, au lieu de les coller dans le répertoire via l'Explorateur, utilisez Visual Studio pour coller les fichiers dans les dossiers.

Kamranicus
la source
-1

J'ai réalisé que la meilleure solution pour cela était d'ajouter manuellement des fichiers, un par un. Si vous en avez des centaines comme moi, ce n'était qu'une question de quelques heures. C'est drôle que même en 2016 avec VS 2015, ce grave problème ne soit toujours pas résolu. Ahh, comme j'aime Xcode.

Marcin Skoczylas
la source