Maui Blazor 中文社区 QQ群:645660665

MAUI 嵌入式 Web 架构实战(五) 构建完整的 Web Admin 管理后台

MAUI 嵌入式 Web 架构实战(五)

使用 PicoServer 构建完整 Web Admin 管理后台

源码地址
https://github.com/densen2014/MauiPicoAdmin


一、从 API Server 到完整应用

在前几篇文章中,我们已经逐步构建了 PicoServer 在 MAUI 中的核心能力:

第一篇

在 MAUI 中嵌入 PicoServer 本地 Web 服务。

第二篇

实现 PicoServer 路由机制与 API 设计。

第三篇

构建可扩展的 REST API 架构:

Controller
Service
Model

第四篇

实现静态文件托管,让 PicoServer 可以运行 Web 页面。

此时我们的系统已经具备:

本地 Web Server
本地 REST API
本地 Web 前端

也就是说:

一个完整 Web 应用的基础设施已经具备。

接下来我们要做一件更重要的事情:

构建真正可用的 Web Admin 管理后台

例如:

商品管理
设备管理
系统配置
日志查看

最终效果类似:

localhost:8090
↓
Admin Dashboard
↓
API
↓
MAUI 本地逻辑

二、Web Admin 架构

在 PicoServer + MAUI 架构下,一个完整后台系统结构如下:

                 ┌─────────────────────┐
                 │      Web Admin      │
                 │ Vue / React / UI    │
                 └──────────▲──────────┘
                            │ fetch
                            │
                 ┌──────────┴──────────┐
                 │      PicoServer     │
                 │   Static + REST     │
                 └──────────▲──────────┘
                            │
                     ┌──────┴──────┐
                     │ Controller  │
                     └──────▲──────┘
                            │
                     ┌──────┴──────┐
                     │   Service   │
                     └──────▲──────┘
                            │
                     ┌──────┴──────┐
                     │ MAUI Logic  │
                     └─────────────┘

核心思想:

UI 使用 Web 技术
API 使用 PicoServer
逻辑使用 C#

这种模式在很多系统中都非常常见,例如:

工业设备系统
IoT 管理平台
本地控制系统
嵌入式设备后台

三、选择 Admin UI 框架

开发后台界面通常不需要从零开始。

可以直接使用成熟的 Admin UI。

推荐几个常用方案:

Bootstrap Admin

最简单方案:

Bootstrap
Chart.js
jQuery

适合:

轻量后台
快速开发

Vue Admin

常见方案:

Vue
Element Plus
Vite

优点:

组件丰富
开发效率高
生态成熟

React Admin

技术栈:

React
Ant Design

适合:

复杂系统
大型后台

在本系列中,为了简单,我们先使用:

原生 HTML + Bootstrap

后续可以升级到 Vue。


四、创建 Admin 页面

wwwroot 目录创建:

wwwroot
 ├─ index.html
 ├─ product.html
 ├─ css
 └─ js

index.html

<!DOCTYPE html>
<html>

<head>

<meta charset="utf-8">

<title>PicoServer Admin</title>

<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
rel="stylesheet">

</head>

<body class="container">

<h1 class="mt-4">PicoServer Admin</h1>

<div class="mt-4">

<a href="product.html" class="btn btn-primary">
商品管理
</a>

</div>

</body>
</html>

访问:

http://localhost:8090

就可以看到后台首页。


五、商品管理页面

创建:

product.html

页面结构

<h2>商品管理</h2>

<button onclick="loadProducts()">
加载商品
</button>

<table id="table">

<thead>

<tr>

<th>ID</th>
<th>名称</th>
<th>价格</th>

</tr>

</thead>

<tbody></tbody>

</table>

六、调用 API 加载数据

添加 JavaScript:

async function loadProducts()
{
    let res = await fetch("/api/product/list");

    let json = await res.json();

    let list = json.data;

    let tbody = document.querySelector("#table tbody");

    tbody.innerHTML = "";

    for(let p of list)
    {
        let row = `
        <tr>
        <td>${p.id}</td>
        <td>${p.name}</td>
        <td>${p.price}</td>
        </tr>
        `;

        tbody.innerHTML += row;
    }
}

此时:

页面
↓
fetch API
↓
PicoServer
↓
返回 JSON
↓
渲染表格

七、API 实现

Controller:

public async Task List(HttpListenerRequest req,
HttpListenerResponse res)
{
    var data = service.GetProducts();

    var result = ApiResult.Success(data);

    string json = JsonSerializer.Serialize(result);

    res.ContentType = "application/json";

    await res.WriteAsync(json);
}

Service:

public List<object> GetProducts()
{
    return new List<object>
    {
        new { id = 1, name = "Apple", price = 10 },
        new { id = 2, name = "Orange", price = 8 }
    };
}

页面完整代码

<!DOCTYPE html>
<html>

<head>

    <meta charset="utf-8">

    <title>PicoServer Admin</title>

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
          rel="stylesheet">

</head>

<body class="bg-light">
    <div class="container py-5">
        <div class="row justify-content-center">
            <div class="col-lg-8">
                <div class="card shadow-sm">
                    <div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
                        <h4 class="mb-0">商品管理</h4>
                        <button onclick="loadProducts()" class="btn btn-light btn-sm">
                            <span class="bi bi-arrow-repeat"></span> 加载商品
                        </button>
                    </div>
                    <div class="card-body">
                        <div id="spinner" class="text-center my-3" style="display:none;">
                            <div class="spinner-border text-primary" role="status">
                                <span class="visually-hidden">Loading...</span>
                            </div>  
                        </div>
                        <div class="table-responsive">
                            <table id="table" class="table table-striped table-hover align-middle">
                                <thead class="table-primary">
                                    <tr>
                                        <th>ID</th>
                                        <th>名称</th>
                                        <th>价格</th>
                                    </tr>
                                </thead>
                                <tbody></tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <script>
        async function loadProducts() {
            document.getElementById("spinner").style.display = "block";
            let res = await fetch("/api/product/list");
            let json = await res.json();
            let list = json.data;
            let tbody = document.querySelector("#table tbody");
            tbody.innerHTML = "";
            for (let p of list) {
                let row = `
                    <tr>
                        <td>${p.id}</td>
                        <td>${p.name}</td>
                        <td>${p.price}</td>
                    </tr>
                `;
                tbody.innerHTML += row;
            }
            document.getElementById("spinner").style.display = "none";
        }
    </script>
</body>
</html>

image


八、增加 CRUD 功能

后台系统通常需要完整 CRUD。

例如:

新增商品
编辑商品
删除商品
查询商品

API 示例:

GET  /api/product/list
GET  /api/product/detail?id=1
POST /api/product/add
POST /api/product/delete

前端调用:

fetch("/api/product/add")
fetch("/api/product/delete")

九、Admin 后台最终效果

完成后系统结构如下:

localhost:8090

后台页面:

首页
商品管理
系统配置

调用流程:

Web UI
   ↓
fetch API
   ↓
PicoServer
   ↓
Controller
   ↓
Service
   ↓
MAUI Logic

此时你的 MAUI 应用实际上已经变成:

一个完整 Web 应用容器


十、为什么这种架构非常强

这种架构在很多场景下非常有优势。

例如:

1 工业设备系统

设备控制
参数配置
日志查看

2 IoT 系统

设备管理
数据展示
远程控制

3 本地管理后台

库存系统
POS系统
离线业务系统

4 跨平台 UI

同一套 Web UI 可以运行在:

Windows
Android
iOS
Mac
Linux

十一、WebView App 壳

在 MAUI 中可以直接嵌入:

<WebView Source="http://127.0.0.1:8090" />

应用结构:

MAUI App
   ↓
WebView
   ↓
PicoServer
   ↓
Web Admin

这就是:

Local Web Shell 架构

很多桌面应用其实都在使用类似架构,例如:

VS Code
Slack
Notion

十二、本篇总结

本篇我们完成了整个系列的重要里程碑:

构建完整 Web Admin 管理后台

实现内容包括:

Admin Dashboard 页面
商品管理 CRUD 示例
API 与前端联动
完整 Web Admin 架构

此时我们的 MAUI 应用已经具备:

本地 Web Server
本地 API
本地 Web UI
完整 Admin 系统

下一篇预告

接下来我们将继续升级系统:

MAUI 嵌入式 Web 架构实战(六)

Web Admin 权限系统与登录认证

我们将实现:

用户登录
Token 认证
权限控制
登录拦截
API 鉴权

最终实现一个 真正可用的 Admin 管理系统

posted @ 2026-03-08 09:28  AlexChow  阅读(1110)  评论(0)    收藏  举报