Practical Combat of MAUI Embedded Web Architecture (2)PicoServer Routing Mechanism and API Design
Source: Dev.to
I. Overall Architecture
After embedding PicoServer in a .NET MAUI application, the following embedded‑web architecture can be formed:
Browser / WebView
│
HTTP
│
┌────────────┐
│ PicoServer │
└────────────┘
│
┌──────────────┼──────────────┐
│ │
REST API Web Admin
│ │
└──────────────┬──────────────┘
│
Service Layer
│
MAUI App- PicoServer – handles HTTP requests.
- REST API – provides data interfaces.
- Web Admin – offers an administration interface.
- Service Layer – contains business logic.
- MAUI App – manages device capabilities and local functions.
This pattern enables a mobile or desktop application to be equipped with web‑server capabilities simultaneously.
II. From “Hello PicoServer” to an API Server
In the previous article Practical Combat of MAUI Embedded Web Architecture (I) we completed the basic environment setup:
- Embedded PicoServer in MAUI.
- Launched a local HTTP service.
Access via browser:
Response:
Hello PicoServerThe application now has the capability of a local web server.
In real‑world projects a simple string response is insufficient. A usable local web service typically requires:
- REST API
- JSON data interfaces
- Device‑control interfaces
- Local web administration backend
This article focuses on the routing mechanism and API design methods of PicoServer, upgrading the sample server into a truly usable local API service.
III. What Is a Route?
In a web server, a route defines the mapping between URLs and handler functions, e.g.:
| URL | Processing Logic |
|---|---|
/ | Homepage |
/api/time | Return server time |
/api/device/list | Return device list |
When a browser accesses a route, the processing flow is:
Browser
│
HTTP Request
│
/api/time
│
PicoServer Router
│
Handler Method
│
JSON ResponseThe routing system is a core component of any web service.
IV. Basic Usage of PicoServer Routing
In the first article we already used the simplest route:
MyAPI.AddRoute("/", Hello);Full example
public class PicoAdmin
{
private readonly WebAPIServer MyAPI = new WebAPIServer();
public PicoAdmin()
{
MyAPI.AddRoute("/", Hello);
MyAPI.StartServer();
}
private async Task Hello(HttpListenerRequest request, HttpListenerResponse response)
{
await response.WriteAsync("Hello PicoServer");
}
}Route mapping:
/ → Hello()Visiting / executes Hello().
V. Adding Multiple API Routes
Real projects usually need several APIs, such as:
- Get server time
- Query system status
- Retrieve device list
Define multiple routes:
public PicoAdmin()
{
MyAPI.AddRoute("/", Hello);
MyAPI.AddRoute("/api/time", GetTime);
MyAPI.AddRoute("/api/status", GetStatus);
MyAPI.StartServer();
}Implement the handlers:
private async Task GetTime(HttpListenerRequest request, HttpListenerResponse response)
{
var time = DateTime.Now.ToString();
await response.WriteAsync(time);
}
private async Task GetStatus(HttpListenerRequest request, HttpListenerResponse response)
{
await response.WriteAsync("Server Running");
}Sample response
2026/3/5 14:30:12VI. Designing RESTful APIs
Modern web systems usually adopt RESTful APIs. Example:
| API | Function |
|---|---|
GET /api/product/list | Product list |
GET /api/product/detail?id=1 | Product details |
POST /api/product/add | Add new product |
Advantages:
- Clear interface semantics
- Scalable structure
- Easy for front‑end invocation
In PicoServer this can be expressed as:
MyAPI.AddRoute("/api/product/list", ProductList);
MyAPI.AddRoute("/api/product/detail", ProductDetail);VII. Returning JSON Data
Practical APIs usually return JSON rather than plain strings, e.g.:
{
"code": 0,
"message": "ok",
"data": {
"time": "2026-03-05 14:30:00"
}
}Implementation in C#:
private async Task GetTime(HttpListenerRequest request, HttpListenerResponse response)
{
var result = new
{
code = 0,
message = "ok",
data = new
{
time = DateTime.Now
}
};
string json = System.Text.Json.JsonSerializer.Serialize(result);
response.ContentType = "application/json";
await response.WriteAsync(json);
}VIII. Reading GET Parameters
Many APIs need to read request parameters, such as:
/api/product/detail?id=1001Parameters can be obtained like this:
private async Task ProductDetail(HttpListenerRequest request, HttpListenerResponse response)
{
string id = request.QueryString["id"];
var result = new
{
id = id,
name = "Demo Product",
price = 100
};
string json = JsonSerializer.Serialize(result);
response.ContentType = "application/json";
await response.WriteAsync(json);
}Access address:
http://127.0.0.1:8090/api/product/detail?id=1001
Response received:
{
"id": "1001",
"name": "Demo Product",
"price": 100
}IX. Product List API Example
private async Task ProductList(HttpListenerRequest request, HttpListenerResponse response)
{
var products = new[]
{
new { id = "1", name = "Demo Product 1", price = 100 },
new { id = "2", name = "Demo Product 2", price = 200 },
new { id = "3", name = "Demo Product 3", price = 300 }
};
var result = new
{
code = 0,
message = "ok",
data = products
};
string json = JsonSerializer.Serialize(result);
response.ContentType = "application/json";
await response.WriteAsync(json);
}Access address:
http://127.0.0.1:8090/api/product/list
Response received:
{
"code": 0,
"message": "ok",
"data": [
{ "id": "1", "name": "Demo Product 1", "price": 100 },
{ "id": "2", "name": "Demo Product 2", "price": 200 },
{ "id": "3", "name": "Demo Product 3", "price": 300 }
]
}X. API Routing Design Recommendations
When designing local APIs, follow these rules:
1. Unified API Prefix
Use a common prefix, e.g. /api/*.
Examples
GET /api/product/listGET /api/product/detail?id=1POST /api/product/addDELETE /api/product/delete?id=1
HTTP Method Description
| Method | Action |
|---|---|
| GET | Query |
| POST | Create |
| PUT | Update |
| DELETE | Delete |
2. Unified Response Structure
Adopt a consistent JSON format:
{
"code": 0,
"message": "ok",
"data": {}
}Advantages
- Unified front‑end processing
- Simple error handling
- Clear interface specifications
3. API Module Grouping
Group APIs by business modules:
/api/system/*/api/device/*/api/product/*
This keeps the interface structure clear and easy to maintain.
XI. Typical Application Scenarios of Local APIs
When an HTTP server runs inside an app, many architectural patterns become possible.
1. Local Web Admin
Browser
↓
localhost:8090
↓
PicoServer API
↓
MAUI Local Logic2. WebView + Local API
WebView Page
↓
fetch("/api/product/list")
↓
PicoServer
↓
C# Business Logic3. LAN Device Control
Mobile Phone / PC
↓
http://192.168.1.100:8090
↓
Device Control APICommon scenarios
- IoT device management
- Desktop software backend
- Local console utilities
- Debugging interfaces
XII. Summary of This Article
In this article we completed three key steps:
- Understanding the PicoServer routing mechanism
- Building multiple API interfaces
- Returning standard JSON data
We have upgraded the initial “Hello PicoServer” into a truly usable local REST API service.
Next Article Preview
Practical Combat of MAUI Embedded Web Architecture (III): Building a Scalable PicoServer REST API Framework
Content will include:
- Controller structure design
- Service layer architecture
- Unified API response model
- Global exception handling
- Logging system
The ultimate goal is to build a scalable embedded API framework.
Series Articles
- Embedding PicoServer in MAUI
- PicoServer Routing Mechanism and API Design
- Building a Scalable REST API Framework
- Static File Hosting and Frontend Integration
- Building a Web Admin Backend
- Login Authentication and Permission System
- LAN Access and Device Management
- Local Cache Architecture
- PicoServer + PWA Offline System
- Complete App Web Shell Architecture