PicoServer
Source Code URL:
https://github.com/densen2014/MauiPicoAdmin
I. Why WebSocket Is Needed
In the previous articles, we have implemented a complete architecture:
Web Admin UI
↓
PicoServer REST API
↓
MAUI Service
↓
SQLite / Device
Web APIs are suitable for:
- CRUD operations
- Request-response workflows
However, for real-time systems, REST APIs have obvious limitations.
For example:
| Scenario | Issues with REST API |
|---|---|
| Device status changes | Requires continuous polling |
| Real-time logging | High latency |
| Device control | Slow interaction |
Take browsers as an example: they send a request to /api/device/status every second. This is called Polling.
Problems with polling:
- High server load
- High latency
- Poor user experience
The solution is WebSocket.
II. What Is WebSocket
WebSocket is a persistent connection communication protocol.
Communication mode:
Browser
⇅
WebSocket
⇅
Server
Key features:
| Feature | Description |
|---|---|
| Bidirectional communication | Both client and server can send data |
| Persistent connection | No need to repeatedly establish connections |
| Real-time performance | Millisecond-level latency |
Therefore, it is ideal for:
- Device control
- Real-time logging
- Message pushing
- IoT systems
III. System Architecture Upgrade
After integrating WebSocket, the architecture becomes:
Web Admin
│
┌──────┴───────┐
│ │
REST API WebSocket
│ │
▼ ▼
PicoServer
│
▼
Service
│
▼
Device / DB
REST API: Handles CRUD operations
WebSocket: Manages real-time communication and device control
IV. Code Implementation of WebSocket Server
Add a WebSocketManager to PicoServer.
Create the file: Services/WebSocketManager.cs
Sample implementation:
using PicoServer;
public class WebSocketManager
{
private WebAPIServer? api;
public void RegisterWebSocket(WebAPIServer api)
{
this.api = api;
api.enableWebSocket = true;
api.WsOnConnectionChanged = WsConnectChanged;
api.WsOnMessage = OnMessageReceived;
}
public async Task OnMessageReceived(string clientId, string message, Func<string, Task> reply)
{
await reply("Received!");
var clients = api!.WsGetOnlineClients();
foreach (var client in clients)
{
await api.WsSendToClientAsync(client, $"{clientId} says: {message}");
}
}
public async Task WsConnectChanged(string clientId, bool connected)
{
await api!.WsBroadcastAsync($"{clientId} {connected}");
}
}
This component implements:
- Connection management
- Message reception
- Message broadcasting
V. Register WebSocket Routes
Register WebSocket in the ServerHost:
ws.RegisterWebSocket(api);
Now browsers can connect via:
ws://localhost:8090/ws
VI. Frontend WebSocket Connection
In the Web Admin interface:
const ws = new WebSocket("ws://127.0.0.1:8090/ws");
ws.onopen = () => {
console.log("WebSocket Connected");
};
ws.onmessage = (event) => {
console.log("Message:", event.data);
};
ws.onclose = () => {
console.log("Disconnected");
};
function send() {
ws.send("hello device");
}
Send messages with:
ws.send("hello device");
VII. Device Control Protocol Design
In practical systems, you need to define a communication protocol. JSON is recommended.
Examples:
Device control:
{
"type": "device_control",
"device": "printer",
"cmd": "start"
}
Device status:
{
"type": "device_status",
"device": "printer",
"status": "running"
}
Log message:
{
"type": "log",
"message": "device started"
}
VIII. Server-Side Device Command Handling
Parse WebSocket messages:
var cmd = JsonSerializer.Deserialize<WsCommand>(msg);
switch(cmd.Type)
{
case "device_control":
DeviceService.Execute(cmd.Device, cmd.Cmd);
break;
}
Example:
DeviceService.Execute("printer","start");
IX. Real-Time Device Status Pushing
When device status changes:
await ws.Broadcast(JsonSerializer.Serialize(new
{
type = "device_status",
device = "printer",
status = "running"
}));
The frontend receives the message immediately:
ws.onmessage = e => {
let msg = JSON.parse(e.data);
if(msg.type === "device_status")
{
updateUI(msg);
}
}
This enables real-time updates in the flow: Device → Server → Web Admin
Click to expand complete sample code
Click to expand complete backend code
X. Real-Time Logging System
For device logs:
await ws.Broadcast(JsonSerializer.Serialize(new
{
type="log",
message="print job started"
}));
Frontend implementation:
if(msg.type==="log"){
logPanel.append(msg.message)
}
Effect: A real-time log window
XI. Complete Real-Time Architecture
The final system architecture is:
Web Admin UI
/ \
REST API WebSocket
│ │
▼ ▼
PicoServer Core
│
▼
Services
│
┌─────────┴─────────┐
▼ ▼
SQLite Device
The system's capabilities are now upgraded to include:
- Backend management
- Real-time communication
- Device control
- Data storage
XII. Summary of This Article
In this article, we added the following core capabilities to the system:
- WebSocket real-time communication
- Device control protocol
- Real-time log pushing
- Status synchronization
The system now integrates:
- Web Admin
- REST API
- WebSocket
- Device control
It can be applied to scenarios such as:
- IoT systems
- Device management platforms
- Local control software
- Industrial tool systems
Next Article Preview
The next article will take a crucial step in architecture upgrading:
Practical Combat of MAUI Embedded Web Architecture (8)
Plug-In API Architecture: Automatic Controller Discovery and Modular Expansion
We will implement:
- Plug-in loading
- Module expansion
- Dynamic APIs
- Module management
Ultimately, we will upgrade the system into a truly scalable local web platform.
Top comments (0)