关于 dotnet-file-based-apps
此技能介绍如何使用 .NET 10 SDK,从单个 `.cs` 文件构建、运行和发布 C# 应用,无需 `.csproj`。面向脚本、实用程序和小型应用,涵盖指令、命令行流程及迁移到项目形式。
主要功能
- 01使用 `#:` 指令配置应用
- 02管理 NuGet 包和 SDK 设置
- 03通过命令行运行、构建和发布
- 04从标准输入运行及使用 Unix shebang
- 05将文件转换为项目形式
适用场景
- 01无需项目脚手架创建小型 C# 工具
- 02从 Shell 输入运行 C# 代码片段
- 03将单文件应用打包为 .NET Tool
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wshaddix/ dotnet-skills --skill dotnet-file-based-apps安装后在 Claude Code 中输入/dotnet-file-based-apps确认已加载。
详细介绍
dotnet-file-based-apps
.NET 10 SDK 的基于文件的应用可让你通过单个 .cs 文件构建、运行和发布 C# 应用,无需创建 .csproj 项目文件。SDK 会根据源文件中嵌入的 #: 指令自动生成项目配置。此功能适用于脚本、实用工具和小型应用,这些场景无需传统的项目框架搭建。
这与文件 I/O 无关。 关于 FileStream、RandomAccess、FileSystemWatcher 和路径处理,请参阅 [skill:dotnet-file-io]。
先决条件: 需要 .NET 10 SDK 或更高版本。运行 [skill:dotnet-version-detection] 以确认 SDK 版本。
交叉引用:[skill:dotnet-version-detection] 用于 SDK 版本判断,[skill:dotnet-project-analysis] 用于基于项目的分析(基于文件的应用没有 .csproj),[skill:dotnet-scaffold-project] 用于基于 csproj 的项目框架搭建。
指令概览
基于文件的应用使用 #: 指令配置生成过程。指令是 SDK 级别的指令,而非 C# 语法。它们必须出现在 .cs 文件顶部,位于任何 C# 代码之前。
支持四种指令类型:
| 指令 | 用途 | 示例 |
|---|---|---|
#:package | 添加 NuGet 包引用 | #:package [email protected] |
#:sdk | 设置 SDK(默认:Microsoft.NET.Sdk) | #:sdk Microsoft.NET.Sdk.Web |
#:property | 设置 MSBuild 属性 | #:property PublishAot=false |
#:project | 引用另一个项目文件 | #:project ../Lib/Lib.csproj |
#:package 指令
添加 NuGet 包引用。指定包名称,后面可选地跟上 @version。
#:package Newtonsoft.Json
#:package [email protected]
#:package Spectre.Console@*
版本行为:
@version—— 固定到特定版本@*—— 使用最新稳定版本(NuGet 浮动版本)- 不指定版本 —— 仅当已通过
Directory.Packages.props文件配置了中央包管理(CPM)时才有效;否则,请明确指定版本或使用@*
#:sdk 指令
指定要使用的 SDK。若省略,则默认为 Microsoft.NET.Sdk。
#:sdk Microsoft.NET.Sdk.Web
#:sdk [email protected]
使用此指令启用特定 SDK 的功能。例如,Microsoft.NET.Sdk.Web 可启用 ASP.NET Core 功能,并在生成过程中自动包含 *.json 配置文件。
#:property 指令
设置 MSBuild 属性值。使用此指令自定义生成行为。
#:property TargetFramework=net10.0
#:property PublishAot=false
条件属性值
属性指令支持 MSBuild 属性函数和表达式,可用于条件配置。
带默认值的环境变量:
#:property LogLevel=$([MSBuild]::ValueOrDefault('$(LOG_LEVEL)', 'Information'))
条件表达式:
#:property EnableLogging=$([System.Convert]::ToBoolean($([MSBuild]::ValueOrDefault('$(ENABLE_LOGGING)', 'true'))))
#:project 指令
引用另一个项目文件,或包含项目文件的目录。使用此指令可在基于文件的应用与传统项目之间共享代码。
#:project ../SharedLibrary/SharedLibrary.csproj
被引用的项目会像 .csproj 中的 <ProjectReference> 一样进行生成,并作为项目引用链接。
CLI 命令
.NET CLI 支持通过常见命令使用基于文件的应用。
运行
# Preferred: pass file directly
dotnet run app.cs
# Explicit --file option
dotnet run --file app.cs
# Shorthand (no 'run' subcommand)
dotnet app.cs
# Pass arguments after --
dotnet run app.cs -- arg1 arg2
当当前目录中存在 .csproj 时,dotnet run app.cs(不带 --file)会运行该项目,并将 app.cs 作为参数传递,以保持向后兼容。使用 dotnet run --file app.cs 可强制以基于文件的方式执行。
从 stdin 传入
echo 'Console.WriteLine("hello");' | dotnet run -
- 参数会从标准输入读取 C# 代码,适用于快速测试和集成 shell 脚本。
生成
dotnet build app.cs
默认情况下,生成输出位于系统临时目录下的缓存位置。可通过 --output 或 #:property OutputPath=./output 覆盖。
清理
# Clean build artifacts for a specific file
dotnet clean app.cs
# Clean all file-based app caches in the current directory
dotnet clean file-based-apps
# Clean caches unused for N days (default: 30)
dotnet clean file-based-apps --days 7
发布
dotnet publish app.cs
基于文件的应用默认启用 native AOT。输出位于 .cs 文件旁的 artifacts 目录中。使用 #:property PublishAot=false 可禁用 AOT。
打包为 .NET 工具
dotnet pack app.cs
基于文件的应用默认设置 PackAsTool=true。使用 #:property PackAsTool=false 可禁用此设置。
还原
dotnet restore app.cs
还原会在生成/运行时隐式执行。向 dotnet build 或 dotnet run 传递 --no-restore 可跳过还原。
Shell 执行(Unix)
在类 Unix 系统上使用 shebang 行启用直接执行。
#!/usr/bin/env dotnet
#:package Spectre.Console
using Spectre.Console;
AnsiConsole.MarkupLine("[green]Hello, World![/]");
chmod +x app.cs
./app.cs
文件必须使用 LF 换行符(而非 CRLF),且不得包含 BOM。
启动配置文件
基于文件的应用支持启动配置文件:在源文件所在目录中放置一个扁平的 [AppName].run.json 文件。对于 app.cs,创建 app.run.json:
{
"profiles": {
"https": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
使用 --launch-profile 选择配置文件:
dotnet run app.cs --launch-profile https
如果 app.run.json 和 Properties/launchSettings.json 同时存在,则优先使用传统位置的文件。
用户机密
基于文件的应用会根据文件的完整路径生成稳定的用户机密 ID。
dotnet user-secrets set "ApiKey" "your-secret-value" --file app.cs
dotnet user-secrets list --file app.cs
隐式生成文件
基于文件的应用会遵循同级或父级目录中的 MSBuild 和 NuGet 配置文件:
Directory.Build.props-- 继承的 MSBuild 属性Directory.Build.targets-- 继承的 MSBuild 目标Directory.Packages.props-- 中央包管理版本nuget.config-- NuGet 包源配置global.json-- 固定 SDK 版本
将基于文件的应用放入同时包含传统项目的存储库时,请注意这些文件。继承的属性可能会导致意外的生成行为。
生成缓存
SDK 会根据源内容、指令、SDK 版本和隐式生成文件缓存生成输出。缓存可以提升重复执行 dotnet run 时的性能。
已知的缓存问题:
- 更改隐式生成文件(
Directory.Build.props等)可能不会触发重新生成 - 将文件移至其他目录不会使缓存失效
- 并发执行同一个基于文件的应用可能导致生成争用错误——先使用
dotnet build app.cs生成,再使用dotnet run app.cs --no-build运行多个实例
使用 dotnet clean app.cs 或 dotnet clean file-based-apps 清除缓存。
文件夹布局
不要将基于文件的应用放在 .csproj 项目的目录树中。该项目的隐式生成配置会造成干扰。
# Recommended layout
repo/
src/
MyProject/
MyProject.csproj
Program.cs
scripts/ # Separate directory for file-based apps
utility.cs
tool.cs
迁移:从基于文件的应用迁移到基于项目的应用
当基于文件的应用不再适合单个文件时,可将其转换为传统项目。
自动转换
dotnet project convert app.cs
这会创建一个以应用命名的新目录,其中包含:
- 一个
.csproj文件,其中包含根据#:指令生成的等效 SDK、属性和包引用 - 一份已移除
#:指令的.cs文件副本
原始 .cs 文件保持不变。
何时转换
在以下情况下,将应用转换为基于项目的应用:
- 需要多个源文件
- 需要超出
#:property支持范围的复杂 MSBuild 自定义配置 - 应用需要使用测试框架运行
dotnet test - 应用需要集成到要求使用
.csproj的 CI/CD 工作流中 - 团队成员需要 IDE 项目支持(解决方案资源管理器等)
默认行为
基于文件的应用在若干默认设置上与基于项目的应用不同:
| 设置 | 基于文件的默认值 | 基于项目的默认值 |
|---|---|---|
Native AOT(PublishAot) | true | false |
打包为工具(PackAsTool) | true | false |
| 生成输出位置 | 系统临时目录 | 项目目录中的 bin/ |
| 发布输出位置 | .cs 文件旁的 artifacts/ | bin/<config>/<tfm>/publish/ |
Agent 常见问题
- 不要混淆基于文件的应用和文件 I/O——
dotnet-file-based-apps涵盖如何在没有项目文件的情况下运行 C#(.NET 10 SDK feature)。对于 FileStream、RandomAccess 和路径处理,请使用 [skill:dotnet-file-io]。 - 不要在 C# 代码后使用
#:指令——所有指令都必须放在文件顶部,位于任何 C# 语句、using指令或命名空间声明之前。SDK 会忽略文件中后续位置的指令。 - 未使用 CPM 时不要省略包版本——只有通过
Directory.Packages.props配置了 Central Package Management 时,#:package SomePackage才能不指定版本。未配置 CPM 时,请使用#:package [email protected]或#:package SomePackage@*。 - 不要假设
dotnet build和dotnet test的工作方式相同——dotnet build app.cs会通过虚拟项目进行编译,但dotnet test不适用于基于文件的应用。若要支持测试框架,请转换为项目。 - 不要将基于文件的应用放在
.csproj项目目录中——项目的隐式构建文件(Directory.Build.props等)会影响基于文件的应用,导致意外行为。请使用单独的目录。 - 并行运行前不要忘记预先构建——并行执行同一个基于文件的应用会导致构建输出冲突。请先使用
dotnet build app.cs构建,再使用dotnet run app.cs --no-build运行各个实例。 - 不要忘记向后兼容性——当当前目录中存在
.csproj时,dotnet run app.cs会将app.cs作为参数传递给项目,而不是将其作为基于文件的应用运行。请使用dotnet run --file app.cs强制按基于文件的方式执行。 - 使用 shebang 时不要使用
CRLF行尾——Unix shebang 执行要求使用LF行尾且不能带 BOM。使用CRLF的文件会因/usr/bin/env: 'dotnet\r': No such file or directory而执行失败。