ฉันจะรับแอพไฟล์เดี่ยว. NET Core 3 ของฉันเพื่อค้นหาไฟล์ appsettings.json ได้อย่างไร


11

ควรกำหนดค่าแอปพลิเคชันไฟล์. Net Core 3.0 Web API แบบเดี่ยวให้ค้นหาappsettings.jsonไฟล์ที่อยู่ในไดเรกทอรีเดียวกันกับที่มีไฟล์แอปพลิเคชันเดี่ยวสร้างอยู่หรือไม่

หลังจากวิ่ง

dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true

ไดเรกทอรีมีลักษณะดังนี้:

XX/XX/XXXX  XX:XX PM    <DIR>          .
XX/XX/XXXX  XX:XX PM    <DIR>          ..
XX/XX/XXXX  XX:XX PM               134 appsettings.json
XX/XX/XXXX  XX:XX PM        92,899,983 APPNAME.exe
XX/XX/XXXX  XX:XX PM               541 web.config
               3 File(s)     92,900,658 bytes

อย่างไรก็ตามการพยายามเรียกใช้APPNAME.exeผลลัพธ์ในข้อผิดพลาดต่อไปนี้

An exception occurred, System.IO.FileNotFoundException: The configuration file 'appsettings.json' was not found and is not optional. The physical path is 'C:\Users\USERNAME\AppData\Local\Temp\.net\APPNAME\kyl3yc02.5zs\appsettings.json'.
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.HandleException(ExceptionDispatchInfo info)
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load(Boolean reload)
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load()
   at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
   at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.BuildCommonServices(AggregateException& hostingStartupErrors)
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
...

ฉันลองวิธีแก้ปัญหาจากคำถามที่คล้ายกัน แต่แตกต่างกันเช่นเดียวกับคำถามอื่น ๆ จาก Stack Overflow

ฉันพยายามที่จะผ่านดังต่อไปนี้เพื่อ SetBasePath()

  • Directory.GetCurrentDirectory()

  • environment.ContentRootPath

  • Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)

แต่ละข้อผิดพลาดเดียวกัน

รากของปัญหาคือPublishSingleFileไบนารีถูกคลายซิปและเรียกใช้จากtempไดเรกทอรี

ในกรณีของแอพไฟล์เดียวนี้ตำแหน่งที่ค้นหาappsettings.jsonคือไดเรกทอรีต่อไปนี้:

C:\Users\USERNAME\AppData\Local\Temp\.net\APPNAME\kyl3yc02.5zs

วิธีการทั้งหมดข้างต้นชี้ไปยังตำแหน่งที่ไฟล์ถูกซิปไปซึ่งแตกต่างจากที่ที่มันถูกเรียกใช้

คำตอบ:


14

ผมพบว่าปัญหาเกี่ยวกับ GitHub นี่PublishSingleFile excluding appsettings not working as expectedบรรดาศักดิ์

ที่ชี้ไปที่ปัญหาอื่นที่นี่ชื่อsingle file publish: AppContext.BaseDirectory doesn't point to apphost directory

ในนั้นทางออกคือการพยายาม Process.GetCurrentProcess().MainModule.FileName

รหัสต่อไปนี้กำหนดค่าแอปพลิเคชันให้ดูที่ไดเรกทอรีที่เรียกใช้แอปพลิเคชันที่ดำเนินการได้เดียวรันจากสถานที่ที่มีการแยกไบนารี

config.SetBasePath(GetBasePath());
config.AddJsonFile("appsettings.json", false);

การGetBasePath()ดำเนินการ:

private string GetBasePath()
{
    using var processModule = Process.GetCurrentProcess().MainModule;
    return Path.GetDirectoryName(processModule?.FileName);
}

คำตอบนี้บวก @ ronald-swaine ด้านล่างนี้สมบูรณ์แบบ การตั้งค่าแอพจะถูกแยกออกจาก exe ที่ให้มาและงานเผยแพร่จะวางไฟล์ของการตั้งค่าไว้ข้างๆ exe ที่ให้มาด้วย
Aaron Hudon

8

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

<ItemGroup>
    <None Include="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <CopyToPublishDirectory>Always</CopyToPublishDirectory>
      <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
    </None>
    <None Include="appsettings.Development.json;appsettings.QA.json;appsettings.Production.json;">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <CopyToPublishDirectory>Always</CopyToPublishDirectory>
      <DependentUpon>appsettings.json</DependentUpon>
      <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
    </None>
  </ItemGroup>

  <ItemGroup>
    <None Include="Views\Test.cshtml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
    </None>
  </ItemGroup>

หากสิ่งนี้ไม่เป็นที่ยอมรับและต้องมีเพียงไฟล์เดียวเท่านั้นฉันผ่านพา ธ ไฟล์เดียวที่แยกเป็นเส้นทางหลักในการตั้งค่าโฮสต์ของฉัน อนุญาตให้ตั้งค่าและมีดโกน (ซึ่งฉันเพิ่มหลังจาก) เพื่อค้นหาไฟล์ตามปกติ

// when using single file exe, the hosts config loader defaults to GetCurrentDirectory
            // which is where the exe is, not where the bundle (with appsettings) has been extracted.
            // when running in debug (from output folder) there is effectively no difference
            var realPath = Directory.GetParent(System.Reflection.Assembly.GetExecutingAssembly().Location).FullName;

            var host = Host.CreateDefaultBuilder(args).UseContentRoot(realPath);

หมายเหตุเพื่อสร้างไฟล์เดียวและไม่มี PDB คุณจะต้อง:

<DebugType>None</DebugType>

Views \ Test.cshtml ในตัวอย่างของคุณมีต่อคอมพิวเตอร์เป้าหมายอย่างไร ฉันมีไฟล์รูปภาพและพจนานุกรมที่ฉันต้องเปิดโดยยึดตามวัฒนธรรม
พอลโคเฮน

@ PaulCohen โดยปกติแล้วฉันจะปรับใช้ไฟล์ทั้งหมดจากตำแหน่งเอาต์พุตที่เผยแพร่โดยใช้ SCP ด้วยการเปลี่ยนแปลงเฉพาะใน csproj (ตัวอย่างแรก) APIs ใด ๆ ที่ใช้ไดเรกทอรีเนื้อหารูทเริ่มต้นจะต้องมีไฟล์อยู่ในไดเรกทอรีการทำงาน ดูเหมือนคุณจะต้องใช้ตัวอย่างที่ 2 เพื่อให้ได้เส้นทางที่แท้จริงของเนื้อหาที่ถูกแยกออกมาดังนั้นวิธีที่คุณสามารถเข้าถึงรูปภาพจากเส้นทางแบบเต็มหรือโดยการตั้งค่ารูทเนื้อหาให้ถูกต้องเพื่อให้เส้นทาง ~ / ... เพื่อภาพสามารถนำมาใช้ในมีดโกน
Ronald Swaine

พื้นหลังของฉันอยู่ในแอปพลิเคชันที่ฝังอยู่ดังนั้นโดยทั่วไปไบนารีเดียวจะถูกเขียนเป็นรอม สิ่งที่ฉันรู้คือมี exe ที่ฉันแชร์ไฟล์ "zip like" ที่คลายตัวเอง ไฟล์ข้อมูลของฉันทั้งหมดอยู่ในนั้นและเมื่อแอปพลิเคชันรันทุกอย่างจะถูกแยกไปยัง temp โดยตรง หากฉันพบว่าฉันสามารถค้นหาไฟล์ข้อมูลของฉัน นอกจากนี้ยังหมายความว่าฉันต้องการตรรกะบางอย่างเพื่อให้ฉันสามารถดีบักใน VS ซึ่งเป็นข้อมูลที่อื่น
พอลโคเฮน

1
ฉันมีการตั้งค่านี้ในขณะนี้และหยุดค้นหาไฟล์แบบสุ่ม
ไปแล้ว

1

แอปพลิเคชันของฉันใช้งานบน. NET Core 3.1 เผยแพร่เป็นไฟล์เดียวและทำงานเป็นบริการ Windows (ซึ่งอาจมีหรือไม่มีผลกระทบกับปัญหา)

วิธีแก้ปัญหาที่เสนอโดยProcess.GetCurrentProcess().MainModule.FileNameที่รูทเนื้อหาทำงานได้สำหรับฉัน แต่ถ้าฉันตั้งค่ารูทเนื้อหาในตำแหน่งที่ถูกต้อง:

งานนี้:

Host.CreateDefaultBuilder(args)
    .UseWindowsService()
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseContentRoot(...);
        webBuilder.UseStartup<Startup>();
    });

สิ่งนี้ไม่ทำงาน:

Host.CreateDefaultBuilder(args)
    .UseWindowsService()
    .UseContentRoot(...)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
    });
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.