¿Hay alguna forma de incluir automáticamente archivos de contenido en el archivo de proyecto asp.net?

86

Con frecuencia agrego muchos archivos de contenido (principalmente imágenes y js) a mi proyecto ASP.NET. Estoy usando el sistema de publicación VS, y al publicar, los archivos nuevos no se publican hasta que los incluyo en el proyecto. Me gustaría incluir automáticamente todos los archivos en el directorio especificado. ¿Hay alguna forma de especificar qué directorios deben incluirse automáticamente en el archivo csproj o en cualquier otro lugar?

Marko
fuente
ver: esto puede ayudarlo a stackoverflow.com/questions/1743432/…
Saar
1
no es exactamente lo que estoy buscando
Marko
Actualicé mi respuesta con respecto a su problema al modificar la carpeta dentro de su navegador de soluciones vs.
Filburt

Respuestas:

134

Viejo hilo, lo sé, pero encontré una manera de hacer esto que sigo olvidando, y en mi búsqueda para encontrarlo por última vez, me topé con esta pregunta. La mejor manera que he encontrado para esto es usar el destino BeforeBuild en el archivo .csproj.

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

VS 2010 no tocará esta sección y garantiza que sus archivos se incluyan como contenido cada vez que se compile el proyecto.

Chris
fuente
¿Cuál es el significado de .less? ¿Y qué significa toda la cadena **\*.less?
Usuario registrado
3
Los archivos .less son archivos css destinados a ser analizados por el preprocesador Less CSS. Google "dot less" para obtener más información al respecto. La expresión **\*.lesssignifica incluir todos los archivos * .less en todos los directorios. En lenguaje MSBUILD, ** significa 'todos los directorios de forma recursiva'
Chris
4
Al menos en VS 2012, tan pronto como agrega / elimina un archivo del proyecto y lo guarda, desafortunadamente se expande a la lista completa. :(
Chris Phillips
3
Esto funcionó para mi situación solo después de cambiar BeforeBuild a AfterBuild, mi compilación inicia un script de PowerShell que mueve archivos, que luego no serían recogidos por mi intento de implementación web azul porque solo existían después de que la compilación fue exitosa. Ver "BeforeBuild" me indicó que probablemente también había un "AterBuild". Espero que esto ayude a alguien más.
Luke Rice
1
@John vea mi respuesta a continuación para obtener una solución a VS2015 +.
Jesse
54

Simplemente puede ampliar el archivo .csproj de su sitio web. Simplemente agregue su carpeta raíz de contenido con un comodín recursivo:

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

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

Si lo hace, esta carpeta y todo el contenido a continuación estarán visibles dentro de su navegador de soluciones.

Si intenta ocultar la carpeta dentro del navegador de soluciones especificando

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

No será publicada.


Actualizar

Como ya descubrió, el comodín se reemplazará tan pronto como toque la carpeta dentro de su solución porque los proyectos de VS no están diseñados para contener contenido arbitrario.

Por lo tanto, deberá asegurarse de que la carpeta y su contenido nunca se modifiquen desde VS; agregar o eliminar archivos solo se puede hacer en el sistema de archivos ... que es lo que quería cuando entendí su pregunta.

Sería más fácil si la carpeta pudiera estar oculta en VS pero no pude encontrar una manera de ocultarla Y publicarla.

Otro enfoque fallido fue incluir la carpeta en una CreateItemtarea. Esto dio como resultado que el contenido de la carpeta se publicara en \ bin \ app.publish \ ... y no se me pudo convencer para publicarlo junto con los elementos de contenido dentro del .csproj, por lo que no lo presenté en mi respuesta.

Filburt
fuente
3
Funciona hasta que agrego o elimino el archivo manualmente. Después de esa línea, <Content Include = "Images * *. " /> Desaparece del archivo del proyecto.
Marko
2
@Marko tiene razón. Después de agregarlo <Content Include="Images\**\*.*" />funcionó. Una vez que agregas más imágenes, el .csproj cambia y vuelve a listar todos los archivos en las imágenes / ... y el <Contenido Incluido = "Imágenes * *. " /> Desaparece.
Ravi Ram
Pegue este código en un archivo .proj separado y llámelo desde el destino de compilación anterior en el archivo .csproj.
NL - Disculparse con Monica
21

Para aquellos que tengan problemas para usar la respuesta de Chris , esta es la solución para Visual Studio 2012 y versiones posteriores:

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

Como Chris mencionó en su respuesta, Visual Studio no tocará esto<Target> sección, incluso si manipula manualmente (agregando / eliminando archivos) con el directorio de destino.

Tenga en cuenta que debe incluir un subdirectorio donde se encuentran los archivos (en el caso anterior, es images). Visual Studio / MSBuild colocará esos archivos en el mismo directorio dentro de la estructura del proyecto. Si no usa un subdirectorio, los archivos se colocarán en la raíz de la estructura del proyecto.

Para una explicación rápida de los comodines:

  • **significa todo de forma recursiva (archivos, subdirectorios y archivos dentro de esos)
  • *.ext incluirá todos los archivos con extensión ext dentro del directorio de nivel superior, pero no los subdirectorios
    • Por ejemplo, *.extpodría ser *.png, *.jsetc. Cualquier extensión de archivo funcionará
  • **\*.extincluirá todos los archivos con extensión extdel directorio de nivel superior y todos los subdirectorios.
  • Vea la respuesta de ¿Cómo uso los patrones de nomenclatura Nant / Ant? para una explicación más completa con ejemplos.

Para completar, tenga en cuenta que hay una diferencia entre usar <Target> y no usarlo.

Con el <Target>enfoque, Visual Studio no mostrará los archivos dentro del Explorador de soluciones.

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

El no <Target>enfoque indicará a Visual Studio que muestre los archivos dentro del Explorador de soluciones. El inconveniente de este es que cualquier manipulación de los directorios automáticos hará que Visual Studio anule la entrada comodín. También debe tenerse en cuenta que el enfoque a continuación solo actualizará el Explorador de soluciones al abrir la Solución / Proyecto en VS. Incluso el botón de la barra de herramientas "actualizar" del Explorador de soluciones no lo hará.

<ItemGroup>
  <Content Include="images\**" />
</ItemGroup>
Jesse
fuente
1
Gracias por experimentar y señalar las diferencias entre usar <Target> y no. Gran explicación de los detalles de los comodines también.
Kurt Hutchinson
@KurtHutchinson, no hay problema. =)
Jesse
Creo que esta solución necesita pulirse. Cuando le indica al objetivo que se ejecute después de "BeforeBuild", en teoría, esto también podría ocurrir DESPUÉS de la publicación. La solución actual probablemente funcione debido a la suerte.
Imre Pühvel
@ ImrePühvel, ¿cómo crees que se realiza la publicación antes del BeforeBuildevento? MSBuild primero debe compilar el proyecto y los binarios antes de que pueda siquiera considerar la publicación.
Jesse
1
No pretendí que la publicación ocurriera antes de la compilación, pero que la declaración no garantiza que los elementos se agreguen al contenido antes de la publicación. El ejemplo de código: .. AfterTargets="BeforeBuild". Es decir, su destino personalizado debe ejecutarse después de BeforeBuild, pero no especifica cuánto después. Aunque, mi error, según el algoritmo de pedido de destino actual debería estar bien: msdn.microsoft.com/en-us/library/ee216359.aspx
Imre Pühvel
10

Puede utilizar el System.IO.Directory.GetFile(string)método del marco y sus sobrecargas para incluir de forma recursiva todos los archivos.

  <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
fuente
Esto fue de gran ayuda para mí; Tengo varios directorios con varios niveles de profundidad y muchos archivos que quería incluir automáticamente y esto convirtió todos esos contenidos en uno. ¡Gracias!
Jay Otterbein
2
Experimenté con esto un poco más y resultó que tiene las mismas limitaciones que Include="**\*.ext"con los comodines.
Steven Liekens
Vaya, ¿el archivo del proyecto incluye ejecutar powershell? ¿Eso es una caja de arena en absoluto? Esa es una hazaña esperando suceder.
Brain2000
No es PowerShell. MSBuild tiene su propia sintaxis para invocar métodos estáticos. Según los documentos, esto se limita a clases de sistema. docs.microsoft.com/en-us/visualstudio/msbuild/… Aunque estoy seguro de que puedes <Exec> powershell con cualquier argumento ...
Steven Liekens
3

He escrito cómo pude hacer que el contenido se creara con un pequeño script de 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`" /> "
}

Esto debería producir la declaración de inclusión necesaria en el indicador de PowerShell

thom schumacher
fuente
2

Puede agregar archivos con enlaces como este, se pueden buscar, se pueden ver, pero no se cierran si intenta cambiarlos, también Visual Studio deja los comodines en su lugar:

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

Esto va dentro del archivo .proj.

chongo2002
fuente
1
Intenté esto y VS reemplaza el comodín con los archivos individuales cuando agrego o elimino un archivo usando VS.
carlin.scott
Esto es muy elegante, pero debe eliminar el comodín del destino del enlace
SimSimY
1

No que yo sepa; sin embargo, mi sugerencia es pegarlos en el proyecto, ya que esto los incluirá de forma predeterminada. Entonces, en lugar de pegarlos en el directorio a través del Explorador, use Visual Studio para pegar los archivos en las carpetas.

Kamranicus
fuente
-1

Me di cuenta de que la mejor solución para esto es agregar archivos manualmente, uno por uno. Si tienes cientos de ellos como yo, fue solo cuestión de unas pocas horas. Es curioso que incluso en 2016 con VS 2015 este grave problema aún no esté resuelto. Ahh, cómo amo Xcode.

Marcin Skoczylas
fuente