基于文件的应用

本文 适用于: ✔️ .NET 10 SDK 及更高版本

基于文件的应用使你可以从单个 C# 文件生成、运行和发布 .NET 应用程序,而无需创建传统的项目文件。 它们提供传统 .NET 项目的轻型替代方法。 此方法简化了脚本、实用工具和小型应用程序的开发。 .NET SDK 会根据源文件中的指令自动生成必要的项目配置。

主要优势包括:

  • 减少了简单应用程序的样板代码。
  • 具有嵌入式配置的自包含源文件。
  • 默认情况下启用本机 AOT 发布。
  • 自动打包为 .NET 工具。

本文介绍如何有效地创建、配置和使用基于文件的应用。

支持的指令

基于文件的应用使用带有 #: 前缀的指令来配置生成并运行应用程序。 支持的指令包括: #:package#:project#:property#:sdk。 将这些指令放在 C# 文件的顶部。

#:package

向应用程序添加 NuGet 包引用。

#:package Newtonsoft.Json
#:package Serilog version="3.1.1"

#:project

引用包含项目文件的另一个项目文件或目录。

#:project ../SharedLibrary/SharedLibrary.csproj

#:property

设置 MSBuild 属性值。

#:property TargetFramework=net10.0
#:property PublishAot=false

#:sdk

指定要使用的 SDK。 默认为 Microsoft.NET.Sdk

#:sdk Microsoft.NET.Sdk.Web

CLI 命令

.NET CLI 通过熟悉的命令完全支持基于文件的应用。

运行应用程序

使用 dotnet run 以下命令直接运行基于文件的应用:

dotnet run file.cs

也可以使用简写语法:

dotnet file.cs

传递参数

通过多种方式将参数传递给应用程序:

dotnet run file.cs -- arg1 arg2

-- 后的参数传递给应用程序。 如果没有 --,参数将转到 dotnet run 命令:

dotnet run file.cs arg1 arg2

但是,使用速记语法,所有参数都转到应用程序:

dotnet file.cs arg1 arg2

生成应用程序

使用 dotnet build 以下命令编译基于文件的应用:

dotnet build file.cs

SDK 生成临时项目并生成应用程序。

清理生成输出

使用 dotnet clean 命令删除构建产物:

dotnet clean file.cs

清理目录中所有基于文件的应用:

dotnet clean file-based-apps

发布应用程序

使用 dotnet publish 以下命令创建部署包:

dotnet publish file.cs

基于文件的应用程序默认启用本机提前编译 (AOT) 发布,生成优化的自包含可执行程序。

打包为工具

使用 dotnet pack 以下命令将基于文件的应用打包为 .NET 工具:

dotnet pack file.cs

默认情况下设置 PackAsTool=true 基于文件的应用。

转换为项目

使用 dotnet project convert 以下命令将基于文件的应用转换为传统项目:

dotnet project convert file.cs

此命令创建 .csproj 具有等效 SDK 和属性的文件。 从文件#中移除所有.cs指令,并将它们转换为相应.csproj文件中的元素。

还原依赖项

使用 dotnet restore 命令还原文件中引用的 NuGet 包:

dotnet restore file.cs

生成或运行应用程序时,还原操作会隐式运行。

默认包含的项目

基于文件的应用会自动包含用于编译和打包的特定文件类型。

默认情况下,包含以下项:

  • 单个 C# 文件本身。
  • 同一目录中的 ResX 资源文件。

不同的 SDK 包括其他文件类型:

  • Microsoft.NET.Sdk.Web 包括 *.json 配置文件。
  • 其他专用 SDK 可能包括其他模式。

本机 AOT 发布

默认情况下,文件型应用程序启用本地预先(AOT)编译。 此功能生成经过优化的自包含可执行文件,且启动速度更快,内存占用量更小。

如果需要禁用本机 AOT,请使用以下设置:

#:property PublishAot=false

有关本机 AOT 的详细信息,请参阅 本机 AOT 部署

用户机密

基于文件的应用根据完整文件路径的哈希生成稳定的用户机密 ID。 此 ID 允许将敏感配置与源代码分开存储。

访问用户机密的方式与传统项目相同:

dotnet user-secrets set "ApiKey" "your-secret-value" --project file.cs

有关详细信息,请参阅 开发中的应用机密的安全存储

启动配置

基于文件的应用支持启动配置文件,用于配置应用程序在开发期间运行方式。 相较于将启动配置文件放在Properties/launchSettings.json中,基于文件的应用程序可以在与源文件相同的目录中使用一个名为[ApplicationName].run.json的平面启动设置文件。

基本启动设置文件

创建以应用程序命名的启动设置文件。 例如,如果基于文件的应用是 app.cs,请在同一目录中创建 app.run.json

{
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

多个基于文件的应用

在同一目录中有多个基于文件的应用时,每个应用都可以有自己的启动设置文件:

📁 myapps/
├── foo.cs
├── foo.run.json
├── bar.cs
└── bar.run.json

用户配置选择

.NET CLI 使用以下优先级选择启动配置文件:

  1. --launch-profile选项指定的配置文件。
  2. DOTNET_LAUNCH_PROFILE环境变量指定的配置。
  3. 启动设置文件中第一个定义的配置文件。

为了按特定配置文件运行,请执行以下操作:

dotnet run app.cs --launch-profile https

传统启动设置

基于文件的应用还支持传统 Properties/launchSettings.json 文件。 如果这两个文件都存在,则传统位置优先。 如果这两个文件都存在,.NET CLI 会记录警告,以阐明使用哪个文件。

Shell 执行

使用 shebang 行和可执行权限,在类似 Unix 的系统上直接执行基于文件的应用。

在文件顶部添加 shebang:

#!/usr/bin/env dotnet
#:package Spectre.Console

using Spectre.Console;

AnsiConsole.MarkupLine("[green]Hello, World![/]");

使文件具有可执行属性:

chmod +x file.cs

直接运行:

./file.cs

隐式生成文件

基于文件的应用遵循同一目录或父目录中的 MSBuild 和 NuGet 配置文件。 这些文件会影响 SDK 如何生成应用程序。 组织基于文件的应用时,请注意这些文件。

Directory.Build.props

定义应用于目录树中的所有项目的 MSBuild 属性。 基于文件的应用继承这些属性。

Directory.Build.targets

定义 MSBuild 目标和自定义生成逻辑。 基于文件的应用在生成过程中执行这些目标。

Directory.Packages.props

为 NuGet 依赖项启用中央包管理。 基于文件的应用可以使用集中管理的包版本。

nuget.config

配置 NuGet 包源和设置。 还原包时,基于文件的应用使用这些配置。

global.json

指定要使用的 .NET SDK 版本。 基于文件的应用遵循此版本选择。

生成缓存

.NET SDK 缓存生成输出以提高后续生成的性能。 基于文件的应用参与此缓存系统。

缓存行为

SDK 基于以下项缓存构建输出:

  • 源文件内容。
  • 指令配置。
  • SDK 版本。
  • 隐式生成文件。

缓存可提高生成性能,但在以下情况下可能会导致混淆:

  • 对隐式生成文件的更改不会触发重新生成。
  • 将文件移动到不同的目录不会使缓存失效。

解决方法

  • 使用 --no-cache 标志运行完整构建:

    dotnet build file.cs --no-cache
    
  • 强制执行清理构建以绕过缓存:

    dotnet clean file.cs
    dotnet build file.cs
    

文件夹布局建议

仔细组织基于文件的应用,以避免与传统项目和隐式生成文件冲突。

避免项目文件重叠

不要将基于文件的应用放置在项目的目录结构 .csproj 中。 项目文件的隐式生成文件和设置可能会干扰基于文件的应用。

不建议:

📁 MyProject/
├── MyProject.csproj
├── Program.cs
└──📁 scripts/
    └── utility.cs  // File-based app - bad location

推荐:

📁 MyProject/
├── MyProject.csproj
└── Program.cs
📁 scripts/
└── utility.cs  // File-based app - good location

注意隐式文件

父目录中的隐式生成文件会影响子目录中所有基于文件的应用。 如果需要不同的生成配置,请为基于文件的应用创建隔离目录。

不建议:

📁 repo/
├── Directory.Build.props  // Affects everything below
├── app1.cs
└── app2.cs

推荐:

📁 repo/
├── Directory.Build.props
├──📁 projects/
│   └── MyProject.csproj
└──📁 scripts/
    ├── Directory.Build.props  // Isolated configuration
    ├── app1.cs
    └── app2.cs

另请参阅