Làm cách nào tôi có thể tải ứng dụng tệp .NET Core 3 của mình để tìm tệp appsinstall.json?


11

Nên cấu hình ứng dụng API Web .Net Core 3.0 một tệp như thế nào để tìm appsettings.jsontệp nằm trong cùng thư mục mà ứng dụng tệp đơn được xây dựng?

Sau khi chạy

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

Thư mục trông như thế này:

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

Tuy nhiên, cố gắng chạy APPNAME.exekết quả trong lỗi sau

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()
...

Tôi đã thử các giải pháp từ một câu hỏi tương tự, nhưng khác biệt , cũng như các câu hỏi Stack Overflow khác.

Tôi đã cố gắng vượt qua những điều sau đây để SetBasePath()

  • Directory.GetCurrentDirectory()

  • environment.ContentRootPath

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

Mỗi cái dẫn đến cùng một lỗi.

Nguyên nhân của vấn đề là PublishSingleFilenhị phân được giải nén và chạy từ một tempthư mục.

Trong trường hợp ứng dụng tệp đơn này, vị trí nó đang tìm appsettings.jsonlà thư mục sau:

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

Tất cả các phương thức trên đều chỉ đến vị trí mà tệp được giải nén, khác với nơi nó được chạy từ đó.

Câu trả lời:


14

Tôi tìm thấy một vấn đề trên GitHub ở đây có tiêu đề PublishSingleFile excluding appsettings not working as expected.

Điều đó chỉ ra một vấn đề khác ở đây có tiêu đềsingle file publish: AppContext.BaseDirectory doesn't point to apphost directory

Trong đó, một giải pháp là thử Process.GetCurrentProcess().MainModule.FileName

Đoạn mã sau đã cấu hình ứng dụng để xem thư mục mà ứng dụng đơn thực thi được chạy từ đó, thay vì vị trí mà các nhị phân được trích xuất.

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

Việc GetBasePath()thực hiện:

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

Câu trả lời này, cộng với @ ronald-swaine dưới đây là hoàn hảo. Các cài đặt ứng dụng được loại trừ khỏi exe được đóng gói và tác vụ xuất bản sẽ đặt các tệp cài đặt ứng dụng cùng với exe được đóng gói.
Aaron Hudon

8

Nếu bạn ổn với việc sử dụng các tệp trong thời gian chạy bên ngoài tệp thực thi, thì bạn có thể chỉ gắn cờ các tệp bạn muốn bên ngoài, trong csproj. Phương pháp này cho phép thay đổi trực tiếp và như vậy ở một vị trí đã biết.

<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>

Nếu điều này không được chấp nhận và phải CHỈ có một tệp duy nhất, tôi chuyển đường dẫn trích xuất một tệp làm đường dẫn gốc trong thiết lập máy chủ của mình. Điều này cho phép cấu hình và dao cạo (mà tôi thêm sau), để tìm các tệp của nó như bình thường.

// 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);

Lưu ý, để thực sự tạo một tệp duy nhất và không có PDB, bạn cũng cần:

<DebugType>None</DebugType>

Làm thế nào để Views \ Test.cshtml trong ví dụ của bạn có được trên máy tính mục tiêu? Tôi có các tệp hình ảnh và từ điển mà tôi cần mở dựa trên Văn hóa,
Paul Cohen

@PaulCohen Tôi thường triển khai tất cả các tệp từ vị trí đầu ra được xuất bản bằng SCP. Chỉ với những thay đổi trong csproj (ví dụ đầu tiên), bất kỳ API nào đang sử dụng thư mục nội dung gốc mặc định sẽ cần phải có sẵn các tệp của chúng trong thư mục làm việc. Có vẻ như bạn cần sử dụng ví dụ thứ 2, để có được đường dẫn thực sự của nội dung được trích xuất, để bạn có thể truy cập hình ảnh từ một đường dẫn đầy đủ hoặc bằng cách đặt gốc nội dung chính xác để đường dẫn ~ / ... để hình ảnh có thể được sử dụng trong dao cạo.
Ronald Swaine

Nền của tôi là trong các ứng dụng nhúng nên một nhị phân duy nhất thường được ghi vào rom. Những gì tôi nhận ra là có exe mà tôi chia sẻ trong một số loại tự giải nén zip như tập tin. Tất cả các tệp dữ liệu của tôi đều ở đó và khi ứng dụng chạy, mọi thứ được trích xuất trực tiếp sang một temp. Nếu tôi thấy rằng tôi có thể tìm thấy các tập tin dữ liệu của tôi. Điều đó cũng có nghĩa là tôi cần một số logic để tôi có thể Gỡ lỗi trong VS nơi dữ liệu ở một nơi khác.
Paul Cohen

1
Tôi có thiết lập này hiện tại và nó ngẫu nhiên dừng tìm kiếm các tập tin.
Đi

1

Ứng dụng của tôi là trên .NET Core 3.1, được xuất bản dưới dạng một tệp và chạy dưới dạng Dịch vụ Windows (có thể có hoặc không có tác động đến vấn đề này).

Giải pháp đề xuất với Process.GetCurrentProcess().MainModule.FileNamechức năng là gốc nội dung hoạt động với tôi, nhưng chỉ khi tôi đặt gốc nội dung ở đúng vị trí:

Những công việc này:

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

Điều này không hoạt động:

Host.CreateDefaultBuilder(args)
    .UseWindowsService()
    .UseContentRoot(...)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
    });
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.