มีวิธีรวมไฟล์เนื้อหาลงในไฟล์โครงการ asp.net โดยอัตโนมัติหรือไม่?


88

ฉันมักจะเพิ่มไฟล์เนื้อหาจำนวนมาก (ส่วนใหญ่เป็นรูปภาพและ js) ในโครงการ ASP.NET ของฉัน ฉันใช้ระบบเผยแพร่ VS และในการเผยแพร่ไฟล์ใหม่จะไม่เผยแพร่จนกว่าฉันจะรวมไว้ในโครงการ ฉันต้องการรวมไฟล์ทั้งหมดในไดเรกทอรีที่ระบุโดยอัตโนมัติ มีวิธีระบุไดเร็กทอรีใดที่ควรรวมอัตโนมัติในไฟล์ csproj หรือที่อื่น ๆ หรือไม่?


ดู: สิ่งนี้อาจช่วยคุณได้stackoverflow.com/questions/1743432/…
ซาร์

1
ไม่ใช่สิ่งที่ฉันกำลังมองหา
Marko

ฉันอัปเดตคำตอบที่เกี่ยวข้องกับปัญหาของคุณเมื่อแก้ไขโฟลเดอร์ภายในเบราว์เซอร์ vs โซลูชันของคุณ
Filburt

คำตอบ:


135

กระทู้เก่าฉันรู้ แต่ฉันพบวิธีที่จะทำสิ่งนี้ที่ฉันลืมไปเรื่อย ๆ และในการค้นหาครั้งสุดท้ายฉันก็สะดุดกับคำถามนี้ วิธีที่ดีที่สุดที่ฉันพบคือใช้เป้าหมาย BeforeBuild ในไฟล์. csproj

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

VS 2010 จะไม่แตะส่วนนี้และจะช่วยให้มั่นใจได้ว่าไฟล์ของคุณจะรวมเป็นเนื้อหาทุกครั้งที่สร้างโครงการ


ความหมายของ .less คืออะไร? แล้วสตริงทั้งหมดหมายถึง**\*.lessอะไร?
ผู้ลงทะเบียน

3
ไฟล์ .less เป็นไฟล์ css ที่ถูกแยกวิเคราะห์โดย Less CSS preprocessor Google "dot less" สำหรับข้อมูลเพิ่มเติมเกี่ยวกับสิ่งนั้น นิพจน์**\*.lessหมายถึงรวมไฟล์ * .less ทั้งหมดในไดเร็กทอรีทั้งหมด ใน MSBUILD พูด ** หมายถึง 'ไดเรกทอรีทั้งหมดซ้ำ'
คริส

4
อย่างน้อยใน VS 2012 ทันทีที่คุณเพิ่ม / ลบไฟล์ออกจากโปรเจ็กต์และบันทึกสิ่งนี้จะถูกขยายเป็นรายการทั้งหมด :(
Chris Phillips

3
สิ่งนี้ใช้ได้กับสถานการณ์ของฉันหลังจากเปลี่ยน BeforeBuild เป็น AfterBuild แล้วบิลด์ของฉันจะเริ่มต้นสคริปต์ powershell ที่ย้ายไฟล์ไปรอบ ๆ ซึ่งจะไม่ถูกดึงขึ้นมาจากความพยายามในการปรับใช้เว็บสีฟ้าของฉันเนื่องจากมีอยู่หลังจากการสร้างสำเร็จเท่านั้น การเห็น "BeforeBuild" ทำให้ฉันรู้ว่าอาจมี "AterBuild" ด้วย หวังว่านี่จะช่วยคนอื่นได้
Luke Rice

1
@ จอห์นดูคำตอบของฉันด้านล่างสำหรับการแก้ไข VS2015 +
Jesse

55

คุณสามารถขยายไฟล์. csproj เว็บไซต์ของคุณได้ เพียงเพิ่มโฟลเดอร์รูทเนื้อหาของคุณด้วยอักขระตัวแทนแบบเรียกซ้ำ:

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

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

เพื่อให้โฟลเดอร์นี้และเนื้อหาทั้งหมดด้านล่างมองเห็นได้ในเบราว์เซอร์โซลูชันของคุณ

หากคุณพยายามซ่อนโฟลเดอร์ภายในเบราว์เซอร์โซลูชันโดยระบุ

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

จะไม่ถูกเผยแพร่


อัปเดต

ตามที่คุณค้นพบแล้วสัญลักษณ์แทนจะถูกแทนที่ทันทีที่คุณแตะโฟลเดอร์ภายในโซลูชันของคุณเนื่องจากโครงการ VS ไม่ได้ออกแบบมาให้มีเนื้อหาตามอำเภอใจ

ดังนั้นคุณจะต้องตรวจสอบให้แน่ใจว่าโฟลเดอร์และเนื้อหาจะไม่ถูกแก้ไขจากภายใน VS - การเพิ่มหรือลบไฟล์สามารถทำได้ในระบบไฟล์เท่านั้น ... ซึ่งเป็นสิ่งที่คุณต้องการเมื่อฉันเข้าใจคำถามของคุณ

มันจะง่ายกว่าถ้าซ่อนโฟลเดอร์ไว้ใน VS แต่ฉันหาวิธีซ่อนและเผยแพร่ไม่ได้

อีกวิธีหนึ่งที่ไม่ประสบความสำเร็จคือการรวมโฟลเดอร์ตามCreateItemงาน สิ่งนี้ส่งผลให้เนื้อหาของโฟลเดอร์ถูกเผยแพร่ไปยัง\ bin \ app.publish \ ...และไม่สามารถมั่นใจได้ว่าจะเผยแพร่พร้อมกับรายการเนื้อหาใน. csproj ดังนั้นฉันจึงไม่ได้นำเสนอในคำตอบของฉัน


3
ใช้งานได้จนกว่าฉันจะเพิ่มหรือลบไฟล์ด้วยตนเอง หลังจากบรรทัดนั้น <Content Include = "Images * *. " /> หายไปจากไฟล์โปรเจ็กต์
Marko

2
@ มาร์คโก้ถูกต้อง หลังจากเพิ่ม<Content Include="Images\**\*.*" />แล้วใช้งานได้ เมื่อคุณเพิ่มรูปภาพเพิ่มเติมแล้ว. csproj จะเปลี่ยนไปและกลับไปแสดงรายการไฟล์ทั้งหมดในรูปภาพ / ... และ <Content Include = "Images * *. " /> หายไป
ราวีราม

ติดรหัสนี้ในไฟล์. proj แยกต่างหากและเรียกใช้จาก before build target ในไฟล์. csproj
NL - ขอโทษโมนิกา

21

สำหรับผู้ที่มีปัญหาในการใช้คำตอบของ Chrisนี่คือโซลูชันสำหรับ Visual Studio 2012 และใหม่กว่า:

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

ดังที่คริสกล่าวไว้ในคำตอบของเขา - Visual Studio จะไม่แตะต้อง<Target>ส่วนนี้แม้ว่าคุณจะเล่นซอ (เพิ่ม / ลบไฟล์) ด้วยตัวเองด้วยไดเร็กทอรีเป้าหมาย

โปรดทราบว่าคุณควรรวมไดเร็กทอรีย่อยที่มีไฟล์อยู่ (ในกรณีด้านบนคือimages) Visual Studio / MSBuild จะวางไฟล์เหล่านั้นไว้ในไดเร็กทอรีเดียวกันภายในโครงสร้างโปรเจ็กต์ หากคุณไม่ใช้ไดเร็กทอรีย่อยไฟล์จะถูกวางไว้ที่รูทของโครงสร้างโปรเจ็กต์

สำหรับคำอธิบายโดยย่อของสัญลักษณ์แทน:

  • **หมายถึงทุกอย่างแบบวนซ้ำ (ไฟล์ไดเร็กทอรีย่อยและไฟล์ภายในไฟล์เหล่านั้น)
  • *.extจะรวมไฟล์ทั้งหมดที่มีนามสกุลextไว้ในไดเร็กทอรีระดับบนสุด แต่ไม่ใช่ไดเร็กทอรีย่อย
    • ยกตัวอย่างเช่น*.extอาจจะ*.png, *.jsฯลฯใด ๆนามสกุลไฟล์จะทำงาน
  • **\*.extจะรวมไฟล์ทั้งหมดที่มีนามสกุลextจากไดเร็กทอรีระดับบนสุดและไดเร็กทอรีย่อยทั้งหมด
  • ดูคำตอบได้จากฉันจะใช้รูปแบบการตั้งชื่อ Nant / Ant ได้อย่างไร? สำหรับคำอธิบายที่สมบูรณ์ยิ่งขึ้นพร้อมตัวอย่าง

เพื่อให้เสร็จสมบูรณ์โปรดทราบว่ามีความแตกต่างระหว่างการใช้<Target>และไม่ใช้

ด้วย<Target>วิธีการนี้ Visual Studio จะไม่แสดงไฟล์ภายใน Solution Explorer

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

<Target>วิธีการที่ไม่ใช่จะสั่งให้ Visual Studio แสดงไฟล์ภายใน Solution Explorer ข้อเสียเปรียบของสิ่งนี้คือการจัดการไดเร็กทอรีอัตโนมัติใด ๆจะทำให้ Visual Studio แทนที่รายการสัญลักษณ์แทน มันก็ควรจะตั้งข้อสังเกตว่าวิธีการดังต่อไปนี้จะเพียงปรับปรุง Explorer โซลูชันเมื่อเปิดโครงการโซลูชั่น / ใน VS. แม้แต่ปุ่มแถบเครื่องมือ "รีเฟรช" ของ Solution Explorer ก็ยังไม่ทำ

<ItemGroup>
  <Content Include="images\**" />
</ItemGroup>

1
ขอขอบคุณที่ทดลองและชี้ให้เห็นความแตกต่างระหว่างการใช้ <เป้าหมาย> และไม่ใช้ คำอธิบายที่ยอดเยี่ยมเกี่ยวกับรายละเอียดของสัญลักษณ์แทนด้วย
Kurt Hutchinson

@KurtHutchinson - ไม่มีปัญหา =)
เจสซี่

ฉันเชื่อว่าโซลูชันนี้ต้องการการขัดเงา เมื่อคุณสั่งให้เป้าหมายทำงานหลังจาก "BeforeBuild" ในทางทฤษฎีแล้วสิ่งนี้อาจเกิดขึ้นได้หลังจากเผยแพร่ วิธีแก้ปัญหาปัจจุบันอาจใช้งานได้เนื่องจากโชคช่วย
Imre Pühvel

@ ImrePühvelอย่างไรคุณคิดเผยแพร่ที่เกิดขึ้นก่อนที่จะBeforeBuildเหตุการณ์? MSBuild ต้องสร้างโครงการและไบนารีก่อนจึงจะสามารถพิจารณาเผยแพร่ได้
Jesse

1
ฉันไม่ได้อ้างว่าการเผยแพร่เกิดขึ้นก่อนสร้าง แต่การประกาศไม่ได้รับประกันว่าจะเพิ่มรายการลงในเนื้อหาก่อนที่จะเผยแพร่ จากตัวอย่างโค้ด: .. AfterTargets="BeforeBuild". ความหมายเป้าหมายที่กำหนดเองของคุณจะต้องดำเนินการหลังจาก BeforeBuild แต่ไม่ได้ระบุจำนวนหลัง แม้ว่าความผิดพลาดของฉันโดยอัลกอริธึมการสั่งซื้อเป้าหมายปัจจุบันก็น่าจะใช้ได้: msdn.microsoft.com/en-us/library/ee216359.aspx
Imre Pühvel

10

คุณสามารถใช้System.IO.Directory.GetFile(string)วิธีการของเฟรมเวิร์กและการโอเวอร์โหลดเพื่อรวมไฟล์ทั้งหมดแบบวนซ้ำได้

  <ItemGroup>
    <Content Include="$([System.IO.Directory]::GetFiles('$(ProjectDir)Scripts\', '*.js', SearchOption.AllDirectories))" />
    <Content Include="$([System.IO.Directory]::GetFiles('$(ProjectDir)Images\', '*.png', SearchOption.AllDirectories))" />
  </ItemGroup>

นี่เป็นความช่วยเหลือที่ยิ่งใหญ่สำหรับฉัน ฉันมีไดเร็กทอรีหลาย ๆ ระดับในระดับลึกและมีไฟล์จำนวนมากที่ฉันต้องการให้รวมไว้โดยอัตโนมัติและสิ่งนี้จะเปลี่ยนเนื้อหาทั้งหมดให้เป็นหนึ่งเดียว ขอบคุณ!
Jay Otterbein

2
ฉันทดลองกับสิ่งนี้มากขึ้นและปรากฎว่าสิ่งนี้มีข้อ จำกัด เช่นเดียวInclude="**\*.ext"กับสัญลักษณ์แทน
Steven Liekens

ว้าวไฟล์โครงการมีการเรียกใช้ powershell หรือไม่ แซนด์บ็อกซ์เลยหรือเปล่า นั่นคือการหาประโยชน์ที่รอให้เกิดขึ้น
Brain2000

ไม่ใช่ PowerShell MSBuild มีไวยากรณ์ของตัวเองสำหรับการเรียกใช้วิธีการแบบคงที่ ตามเอกสารนี้ จำกัด เฉพาะคลาสระบบ docs.microsoft.com/en-us/visualstudio/msbuild/… แม้ว่าฉันแน่ใจว่าคุณสามารถ <Exec> powershell กับข้อโต้แย้งใด ๆ ก็ตาม ...
Steven Liekens

3

ฉันได้เขียนวิธีที่ฉันสามารถรับเนื้อหารวมถึงที่สร้างด้วยสคริปต์พาวเวอร์เชลล์ขนาดเล็ก:

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

สิ่งนี้ควรสร้างคำสั่ง include ที่จำเป็นที่พรอมต์ powershell


2

คุณสามารถเพิ่มไฟล์ที่มีลิงก์เช่นนี้ซึ่งสามารถค้นหาได้ดูได้ แต่จะไม่ชำระเงินหากคุณพยายามที่จะเปลี่ยนแปลงนอกจากนี้สตูดิโอภาพจะทิ้งสัญลักษณ์แทนไว้ด้วย:

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

สิ่งนี้จะอยู่ในไฟล์. proj


1
ฉันลองสิ่งนี้และ VS จะแทนที่สัญลักษณ์แทนด้วยไฟล์แต่ละไฟล์เมื่อฉันเพิ่มหรือลบไฟล์โดยใช้ VS.
carlin.scott

นี่สวยมาก แต่คุณควรลบสัญลักษณ์ออกจากเป้าหมายลิงก์
SimSimY

1

ไม่ใช่ความรู้ของฉัน อย่างไรก็ตามคำแนะนำของฉันคือวางลงในโครงการเนื่องจากจะรวมไว้โดยค่าเริ่มต้น ดังนั้นแทนที่จะวางลงในไดเร็กทอรีผ่าน Explorer ให้ใช้ Visual Studio เพื่อวางไฟล์ลงในโฟลเดอร์


-1

ฉันรู้ว่าทางออกที่ดีที่สุดสำหรับสิ่งนี้คือการเพิ่มไฟล์ด้วยตนเองทีละไฟล์ ถ้าคุณมีหลายร้อยคนเหมือนที่ฉันทำมันก็แค่ไม่กี่ชั่วโมง ตลกดีที่แม้ในปี 2016 VS 2015 ปัญหาร้ายแรงนี้ก็ยังไม่สามารถแก้ไขได้ อ่าฉันรัก Xcode ได้อย่างไร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.