DEV Community

ben
ben

Posted on

Practical Combat of MAUI Embedded Web Architecture (5) Building a Complete Web Admin Backend with PicoServer

PicoServer
Source Code URL:
https://github.com/densen2014/MauiPicoAdmin

I. From API Server to Complete Application

In the previous articles, we have gradually built the core capabilities of PicoServer in MAUI:

Article 1
Embed PicoServer local web service in MAUI.

Article 2
Implement PicoServer routing mechanism and API design.

Article 3
Build a scalable REST API architecture including:

  • Controller
  • Service
  • Model

Article 4
Implement static file hosting to enable PicoServer to run web pages.

At this point, our system already has the following components:

  • Local Web Server
  • Local REST API
  • Local Web Frontend

In other words:
The infrastructure of a complete web application is already in place.

Next, we need to do something more important:
Build a truly usable Web Admin management backend

For example:

  • Product management
  • Device management
  • System configuration
  • Log viewing

The final effect will be similar to this flow:

localhost:8090
↓
Admin Dashboard
↓
API
↓
MAUI Local Logic
Enter fullscreen mode Exit fullscreen mode

II. Web Admin Architecture

Under the PicoServer + MAUI architecture, the structure of a complete backend system is as follows:

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

Core Ideas:

  • Use web technologies for UI
  • Use PicoServer for API
  • Use C# for business logic

This pattern is very common in many systems, such as:

  • Industrial equipment systems
  • IoT management platforms
  • Local control systems
  • Embedded device backends

III. Choosing an Admin UI Framework

Developing backend interfaces usually does not require starting from scratch. You can directly use mature Admin UI frameworks.

Here are several commonly recommended solutions:

Bootstrap Admin

The simplest solution with the tech stack:

  • Bootstrap
  • Chart.js
  • jQuery

Suitable for:

  • Lightweight backends
  • Rapid development

Vue Admin

A common solution with the tech stack:

  • Vue
  • Element Plus
  • Vite

Advantages:

  • Rich component library
  • High development efficiency
  • Mature ecosystem

React Admin

Tech stack:

  • React
  • Ant Design

Suitable for:

  • Complex systems
  • Large-scale backends

In this series, for simplicity, we will first use:
Native HTML + Bootstrap

It can be upgraded to Vue later.

IV. Creating Admin Pages

Create the following files and directories under the wwwroot folder:

wwwroot
 ├─ index.html
 ├─ product.html
 ├─ css
 └─ js
Enter fullscreen mode Exit fullscreen mode

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">
            Product Management
        </a>
    </div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Visit the address:
http://localhost:8090

And you can see the backend homepage.

V. Product Management Page

Create the product.html page with the following structure:

<h2>Product Management</h2>

<button onclick="loadProducts()">
    Load Products
</button>

<table id="table">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody></tbody>
</table>
Enter fullscreen mode Exit fullscreen mode

VI. Calling API to Load Data

Add the following JavaScript code:

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

At this point, the data flow is as follows:

Page
↓
fetch API
↓
PicoServer
↓
Return JSON
↓
Render Table
Enter fullscreen mode Exit fullscreen mode

VII. API Implementation

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);
}
Enter fullscreen mode Exit fullscreen mode

Service

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

Complete Page Code

<!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">Product Management</h4>
                        <button onclick="loadProducts()" class="btn btn-light btn-sm">
                            <span class="bi bi-arrow-repeat"></span> Load Products
                        </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>Name</th>
                                        <th>Price</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>
Enter fullscreen mode Exit fullscreen mode

VIII. Adding CRUD Functions

Backend systems usually require complete CRUD capabilities, such as:

  • Add product
  • Edit product
  • Delete product
  • Query product

API Examples

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

Frontend Calls

fetch("/api/product/add")
fetch("/api/product/delete")
Enter fullscreen mode Exit fullscreen mode

IX. Final Effect of the Admin Backend

After completion, the system structure is as follows:

localhost:8090
Backend Pages:
- Homepage
- Product Management
- System Configuration
Enter fullscreen mode Exit fullscreen mode

Call Flow:

Web UI
   ↓
fetch API
   ↓
PicoServer
   ↓
Controller
   ↓
Service
   ↓
MAUI Logic
Enter fullscreen mode Exit fullscreen mode

At this point, your MAUI application has essentially become:
A complete web application container

X. Why This Architecture Is Powerful

This architecture has significant advantages in many scenarios, such as:

1. Industrial Equipment Systems

  • Equipment control
  • Parameter configuration
  • Log viewing

2. IoT Systems

  • Device management
  • Data display
  • Remote control

3. Local Management Backends

  • Inventory systems
  • POS systems
  • Offline business systems

4. Cross-Platform UI

The same set of Web UI can run on:

  • Windows
  • Android
  • iOS
  • Mac
  • Linux

XI. WebView App Shell

In MAUI, you can directly embed the following code:

<WebView Source="http://127.0.0.1:8090" />
Enter fullscreen mode Exit fullscreen mode

Application Structure:

MAUI App
   ↓
WebView
   ↓
PicoServer
   ↓
Web Admin
Enter fullscreen mode Exit fullscreen mode

This is the Local Web Shell architecture.

Many desktop applications actually use a similar architecture, such as:

  • VS Code
  • Slack
  • Notion

XII. Summary of This Article

In this article, we have achieved an important milestone of the entire series:
Building a complete Web Admin management backend

The implemented contents include:

  • Admin Dashboard page
  • Product management CRUD example
  • API and frontend interaction
  • Complete Web Admin architecture

At this point, our MAUI application has the following capabilities:

  • Local Web Server
  • Local API
  • Local Web UI
  • Complete Admin system

Next Article Preview

Next, we will continue to upgrade the system with:

Practical Combat of MAUI Embedded Web Architecture (6)
Web Admin Permission System and Login Authentication

We will implement:

  • User login
  • Token authentication
  • Permission control
  • Login interception
  • API authentication

Ultimately, we will build a truly usable Admin management system.

Top comments (0)