mcpField
D
dotnet-file-based-apps

dotnet-file-based-apps

github.com/wshaddix开发8671 次安装35 周前更新
代码仓库

关于 dotnet-file-based-apps

此技能介绍如何使用 .NET 10 SDK,从单个 `.cs` 文件构建、运行和发布 C# 应用,无需 `.csproj`。面向脚本、实用程序和小型应用,涵盖指令、命令行流程及迁移到项目形式。

主要功能

  1. 01使用 `#:` 指令配置应用
  2. 02管理 NuGet 包和 SDK 设置
  3. 03通过命令行运行、构建和发布
  4. 04从标准输入运行及使用 Unix shebang
  5. 05将文件转换为项目形式

适用场景

  1. 01无需项目脚手架创建小型 C# 工具
  2. 02从 Shell 输入运行 C# 代码片段
  3. 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)truefalse
打包为工具(PackAsTool)truefalse
生成输出位置系统临时目录项目目录中的 bin/
发布输出位置.cs 文件旁的 artifacts/bin/<config>/<tfm>/publish/

Agent 常见问题

  1. 不要混淆基于文件的应用和文件 I/O——dotnet-file-based-apps 涵盖如何在没有项目文件的情况下运行 C#(.NET 10 SDK feature)。对于 FileStream、RandomAccess 和路径处理,请使用 [skill:dotnet-file-io]。
  2. 不要在 C# 代码后使用 #: 指令——所有指令都必须放在文件顶部,位于任何 C# 语句、using 指令或命名空间声明之前。SDK 会忽略文件中后续位置的指令。
  3. 未使用 CPM 时不要省略包版本——只有通过 Directory.Packages.props 配置了 Central Package Management 时,#:package SomePackage 才能不指定版本。未配置 CPM 时,请使用 #:package [email protected] 或 #:package SomePackage@*。
  4. 不要假设 dotnet build 和 dotnet test 的工作方式相同——dotnet build app.cs 会通过虚拟项目进行编译,但 dotnet test 不适用于基于文件的应用。若要支持测试框架,请转换为项目。
  5. 不要将基于文件的应用放在 .csproj 项目目录中——项目的隐式构建文件(Directory.Build.props 等)会影响基于文件的应用,导致意外行为。请使用单独的目录。
  6. 并行运行前不要忘记预先构建——并行执行同一个基于文件的应用会导致构建输出冲突。请先使用 dotnet build app.cs 构建,再使用 dotnet run app.cs --no-build 运行各个实例。
  7. 不要忘记向后兼容性——当当前目录中存在 .csproj 时,dotnet run app.cs 会将 app.cs 作为参数传递给项目,而不是将其作为基于文件的应用运行。请使用 dotnet run --file app.cs 强制按基于文件的方式执行。
  8. 使用 shebang 时不要使用 CRLF 行尾——Unix shebang 执行要求使用 LF 行尾且不能带 BOM。使用 CRLF 的文件会因 /usr/bin/env: 'dotnet\r': No such file or directory 而执行失败。

参考资料

评论

支持 Markdown