MAUI 嵌入式 Web 架构实战(四) 静态文件托管与前端框架整合
MAUI 嵌入式 Web 架构实战(四)
PicoServer 静态文件托管与 Vue / React 前端整合
源码地址:
https://github.com/densen2014/MauiPicoAdmin
在前几篇文章中,我们已经完成了 PicoServer 在 MAUI 中的核心能力:
- 在 .NET MAUI 应用中嵌入本地 HTTP 服务
- 使用 PicoServer 构建本地 REST API
- 实现 Controller / Service 分层架构
此时我们的应用已经具备:
本地 API Server
但一个完整的应用系统通常包含两部分:
后端 API
前端界面
如果只有 API,仍然无法构建完整应用。
因此在本篇文章中,我们将继续升级 PicoServer,使其具备:
静态文件托管能力
也就是让 MAUI 应用能够直接运行 Web 前端,例如:
HTML
Vue
React
Admin Dashboard
最终实现一个完整的 本地 Web Admin 系统。
整体架构如下:
浏览器 / WebView
│
▼
http://localhost:8090
│
▼
Web Admin
│
fetch API
│
▼
PicoServer
│
▼
MAUI 业务逻辑
一、什么是静态文件托管
静态文件托管指的是服务器直接返回文件,例如:
| URL | 返回文件 |
|---|---|
/ |
index.html |
/css/app.css |
CSS 文件 |
/js/app.js |
JavaScript 文件 |
例如访问:
http://127.0.0.1:8090/index.html
服务器会读取:
wwwroot/index.html
然后返回给浏览器。
这种模式与 传统 Web Server(Nginx / Apache / ASP.NET)完全一致。
二、创建静态资源目录
首先在 MAUI 项目中创建目录:
Resources\Raw\wwwroot
推荐结构:
wwwroot
├─ index.html
├─ css
│ └─ app.css
├─ js
│ └─ app.js
└─ images
这个目录名称在 Web 框架中非常常见,例如:
ASP.NET Core
Spring Boot
Node.js
都使用 Resources\Raw\wwwroot 作为静态目录。
三、创建测试页面
创建一个简单页面:
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PicoServer Admin</title>
</head>
<body>
<h1>PicoServer Web Admin</h1>
<button onclick="loadTime()">获取服务器时间</button>
<p id="result"></p>
<script>
async function loadTime()
{
let res = await fetch("/api/time");
let data = await res.json();
document.getElementById("result").innerText = data.data.time;
}
</script>
</body>
</html>
这个页面会调用之前实现的 API:
/api/time
四、实现静态文件读取
静态文件(index.html)放到工程 Resources\Raw\wwwroot 目录
需要做以下步骤才能实现文件系统
- 定义路径.
public readonly string wwwrootPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot");
- 编辑项目文件,实现每次 Debug/Build 前自动生成 wwwroot/filelist.txt,内容为所有 wwwroot 下的文件相对路径。无需手动维护清单,App 启动时可自动释放所有包内静态文件。

<!--每次 Debug 前自动生成 wwwroot/filelist.txt,内容为 wwwroot 目录下所有文件的相对路径。-->
<Target Name="GenerateWwwrootFileList" BeforeTargets="Build">
<ItemGroup>
<WwwrootFiles Include="Resources\Raw\wwwroot\**\*" />
</ItemGroup>
<WriteLinesToFile
File="Resources\Raw\wwwroot\filelist.txt"
Lines="@(WwwrootFiles->'%(RecursiveDir)%(Filename)%(Extension)')"
Overwrite="true" />
五、释放资源到可写文件夹
由于我们用的是MAUI,除了windows平台能直接访问,其他的平台需要手动释放资源到可写文件夹.
添加如下方法: App 启动时可自动释放所有包内静态文件
public PicoServerHost()
{
EnsureWwwrootExistsAsync().Wait(); //添加这行
RegisterRoutes();
api.StartServer();
}
/// <summary>
/// 每次 Debug/Build 前自动生成 wwwroot/filelist.txt,内容为所有 wwwroot 下的文件相对路径。无需手动维护清单,App 启动时可自动释放所有包内静态文件。
/// </summary>
/// <returns></returns>
private async Task EnsureWwwrootExistsAsync()
{
string wwwrootPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot");
if (!Directory.Exists(wwwrootPath))
{
Directory.CreateDirectory(wwwrootPath);
string[] files;
try
{
using var listStream = await FileSystem.OpenAppPackageFileAsync("wwwroot/filelist.txt");
using var reader = new StreamReader(listStream);
var content = await reader.ReadToEndAsync();
files = content.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
}
catch
{
files = new[] { "index.html" };
}
foreach (var file in files)
{
string destPath = Path.Combine(wwwrootPath, file);
string packagePath = $"wwwroot/{file}";
string destDir = Path.GetDirectoryName(destPath)!;
if (!Directory.Exists(destDir)) Directory.CreateDirectory(destDir);
using var stream = await FileSystem.OpenAppPackageFileAsync(packagePath);
using var fileStream = File.Create(destPath);
await stream.CopyToAsync(fileStream);
}
}
}
六、注册静态路由
在服务器启动时注册路由:
api.AddStaticFiles("/", wwwrootPath);
现在访问:
http://127.0.0.1:8090
就会自动加载:
wwwroot/index.html
七、API 与前端协作
现在整个系统结构变成:
浏览器
↓
index.html
↓
fetch("/api/time")
↓
PicoServer API
↓
MAUI 本地逻辑
例如:
fetch("/api/product/list")
调用接口:
/api/product/list
这种方式有几个优势。
1 无跨域问题
因为:
页面
API
都在同一个服务器:
localhost:8090
2 本地离线运行
整个系统:
HTML
JS
API
数据库
都可以运行在本地。
不依赖外网。
3 Web 技术开发 UI
你可以直接使用:
Vue
React
Bootstrap
Admin Template
开发后台界面。
八、托管 Vue / React 前端
如果使用前端框架,例如 Vue。
构建后会生成:
dist
├─ index.html
├─ assets
└─ js
只需要:
dist → wwwroot
即可。
访问:
http://localhost:8090
整个 Admin 系统即可运行。
九、静态资源缓存优化(推荐)
在 Web Server 中,静态资源通常可以缓存。
例如:
CSS
JS
图片
可以设置缓存 Header:
response.Headers.Add("Cache-Control", "public,max-age=3600");
表示:
浏览器缓存 1 小时
这样可以减少重复请求,提高页面加载速度。
推荐策略:
| 类型 | 缓存时间 |
|---|---|
| HTML | 不缓存 |
| CSS / JS | 1 小时 |
| 图片 | 1 天 |
十、WebView 壳模式
在 MAUI 中可以使用 WebView 打开本地页面:
<WebView Source="http://127.0.0.1:8090/index.html" />
此时应用结构变成:
MAUI App
↓
WebView
↓
localhost:8090
↓
PicoServer
↓
API
这种架构被称为:
Local Web Shell
优点:
UI 使用 Web 技术
逻辑使用 C#
跨平台
添加新的页面
Pages\WebViewPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiPicoAdmin.Pages.WebViewPage"
Title="WebView">
<WebView Source="http://127.0.0.1:8090/index.html" />
</ContentPage>
编辑 AppShell.xaml 添加路由
<ShellContent
Title="WebView"
Icon="{StaticResource IconDashboard}"
ContentTemplate="{DataTemplate pages:WebViewPage}"
Route="webview" />
运行效果

十一、完整架构
现在整个系统已经变成一个完整 Web 架构:
┌───────────────────────┐
│ Web UI │
│ Vue / React / Admin │
└──────────▲────────────┘
│ fetch
│
┌──────────┴────────────┐
│ PicoServer │
│ Static + REST API │
└──────────▲────────────┘
│
┌──────┴──────┐
│ Controller │
└──────▲──────┘
│
┌──────┴──────┐
│ Service │
└──────▲──────┘
│
┌──────┴──────┐
│ MAUI Logic │
└─────────────┘
这种模式常用于:
工业设备管理系统
本地管理后台
嵌入式设备 Web UI
离线业务系统
十二、本篇总结
本篇我们为 PicoServer 增加了一个关键能力:
静态文件托管
新增能力包括:
静态文件服务器
HTML 页面托管
前端调用本地 API
Vue / React 前端整合
WebView 壳架构
此时我们的 MAUI 应用已经具备:
本地 Web Admin 系统
下一篇预告
下一篇我们将继续升级系统:
MAUI 嵌入式 Web 架构实战(五)
构建完整的 Web Admin 管理后台
内容包括:
Admin UI 框架选择
商品管理 CRUD 示例
API 与页面联动
表格、分页、表单设计
最终实现一个真正可用的 本地后台管理系统。
关联项目
FreeSql QQ群:4336577
BA & Blazor QQ群:795206915
Maui Blazor 中文社区 QQ群:645660665
知识共享许可协议
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名AlexChow(包含链接: https://github.com/densen2014 ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系 。
转载声明
本文来自博客园,作者:周创琳 AlexChow,转载请注明原文链接:https://www.cnblogs.com/densen2014/p/19674435
AlexChow
今日头条 | 博客园 | 知乎 | Gitee | GitHub


浙公网安备 33010602011771号