Skip to content

Commit 10cfb2b

Browse files
committed
feat: add .NET10 single file static server documentation; include implementation details and usage instructions
1 parent b8e8c26 commit 10cfb2b

File tree

2 files changed

+64
-34
lines changed

2 files changed

+64
-34
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# .NET10单文件运行之静态服务器
2+
3+
.NET 10 引入了`file-based`功能,也就是单文件运行的功能。不同于其他`脚本`语言,.NET 10 的单文件运行,支持sdk/package等功能,适用范围更广泛。
4+
5+
今天给大家分享一下,我在实际项目中,使用它的一个场景和经验。
6+
7+
## 背景
8+
9+
最近我在完善我的项目`Perigon.CLI`,打算在`2026.01.01`发布,目前已经到了文档完善阶段。
10+
11+
文档是通过静态站点生成工具[`Ater.EasyDocs`](https://github.com/AterDev/EasyDocs)生成的,这是我的另一个开源项目。最近开始升级它,并添加和修复一些功能。
12+
13+
在开发测试过程中,需要对生成后的静态站点进行预览,查看效果。之前我使用的是`Node.js``http-server`来启动一个本地静态服务器。不过由于一个半月前我重装了操作系统,虽然安装了`Node.js`,但是并没有安装`http-server`,我就想到使用一个.cs文件运行`Asp.Net Core`服务,`Asp.Net Core`服务支持加载静态文件,可充当静态服务器。
14+
15+
## 实现
16+
17+
于是我就让AI生成了一个`Asp.Net Core`使用静态文件的代码,然后进行了一些修改,最终代码如下:
18+
```csharp
19+
#:sdk Microsoft.NET.Sdk.Web
20+
// 解析参数:根目录和端口
21+
var baseDir = Directory.GetCurrentDirectory();
22+
var root = args.Length > 0 && !string.IsNullOrWhiteSpace(args[0])
23+
? Path.GetFullPath(args[0])
24+
: Path.Combine(baseDir, "WebSite");
25+
26+
var port = args.Length > 1 && int.TryParse(args[1], out var p) ? p : 5200;
27+
28+
// 创建并配置应用
29+
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
30+
{
31+
Args = args,
32+
ContentRootPath = root,
33+
WebRootPath = root
34+
});
35+
36+
builder.WebHost.UseUrls($"http://localhost:{port}");
37+
38+
var app = builder.Build();
39+
app.UseStaticFiles();
40+
app.MapFallbackToFile("index.html");
41+
42+
await app.RunAsync();
43+
```
44+
45+
我把它保存为`preview.cs`文件。短短20多行代码,我就有了支持指定`目录和端口`的静态服务器,直接使用`dotnet run preview.cs`运行即可。
46+
47+
## 启发
48+
49+
这不是我第一次使用.NET的单文件运行了,对于一些不太复杂,或者没有工程性要求的项目,可以非常方便的编写一个.cs文件来实现需求,它比`Python`更加容易和可靠,只要安装了.NET SDK,不需要打包和发布,就可以直接运行。
50+
51+
对于我遇到的这个场景,我可以节省安装`http-server`的空间,减少`Node.js`生态及工具链的污染,还是非常不错的。
52+
53+
更为重要的是,这是源代码,你可以根据需要进行修改和扩展,不需要去查看命令帮助和文档,完全自定义。

preview.cs

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,24 @@
11
#:sdk Microsoft.NET.Sdk.Web
2+
// 解析参数:根目录和端口
3+
var baseDir = Directory.GetCurrentDirectory();
4+
var root = args.Length > 0 && !string.IsNullOrWhiteSpace(args[0])
5+
? Path.GetFullPath(args[0])
6+
: Path.Combine(baseDir, "WebSite");
27

3-
using Microsoft.Extensions.FileProviders;
4-
var argsList = args ?? Array.Empty<string>();
8+
var port = args.Length > 1 && int.TryParse(args[1], out var p) ? p : 5200;
59

6-
// 1. 解析根目录参数
7-
string rootArg = argsList.Length > 0 && !string.IsNullOrWhiteSpace(argsList[0])
8-
? argsList[0]
9-
: string.Empty;
10-
11-
string baseDir = Directory.GetCurrentDirectory();
12-
string defaultWebRoot = Path.Combine(baseDir, "WebSite");
13-
14-
string root = !string.IsNullOrEmpty(rootArg)
15-
? rootArg
16-
: (Directory.Exists(defaultWebRoot) ? defaultWebRoot : baseDir);
17-
18-
if (!Path.IsPathRooted(root))
19-
{
20-
root = Path.GetFullPath(Path.Combine(baseDir, root));
21-
}
22-
23-
int port = 5200;
24-
if (argsList.Length > 1 && int.TryParse(argsList[1], out var p) && p > 0 && p <= 65535)
25-
{
26-
port = p;
27-
}
10+
// 创建并配置应用
2811
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
2912
{
3013
Args = args,
3114
ContentRootPath = root,
3215
WebRootPath = root
3316
});
3417

35-
builder.WebHost.ConfigureKestrel(options =>
36-
{
37-
options.ListenLocalhost(port);
38-
});
18+
builder.WebHost.UseUrls($"http://localhost:{port}");
19+
3920
var app = builder.Build();
40-
app.UseStaticFiles(new StaticFileOptions
41-
{
42-
FileProvider = new PhysicalFileProvider(root),
43-
RequestPath = "",
44-
});
21+
app.UseStaticFiles();
4522
app.MapFallbackToFile("index.html");
4623

47-
await app.RunAsync();
24+
await app.RunAsync();

0 commit comments

Comments
 (0)