DEV Community

ben
ben

Posted on

Practical Combat of MAUI Embedded Web Architecture (8) Plug-in API Architecture: Automatic Controller Discovery and Modular Expansion

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

In the previous articles of this series, we have gradually built a complete embedded web service architecture based on MAUI + PicoServer, which includes the following components:

  • PicoServer local web server
  • REST API interface system
  • Web Admin management backend
  • Permission authentication system
  • WebSocket real-time communication

As the system continues to expand, a new architectural challenge emerges:

When the number of APIs keeps growing, how can we make the server automatically discover and register APIs instead of manually registering each interface?

For example, the following API modules may emerge in the system one after another:

  • /api/system/*
  • /api/device/*
  • /api/order/*
  • /api/storage/*
  • /api/user/*

If every API needs to be registered manually like this:

api.AddRoute("/api/system/info", SystemInfo, "GET");
api.AddRoute("/api/device/start", DeviceStart, "POST");
api.AddRoute("/api/order/list", OrderList, "GET");
api.AddRoute("/api/storage/add", StorageAdd, "POST");
Enter fullscreen mode Exit fullscreen mode

When the number of interfaces reaches dozens or even hundreds:
The server startup code will become extremely cluttered.

Therefore, in this article, we will implement a more elegant architecture:
API Architecture with Automatic Controller Discovery

Core capabilities include:

  • Marking Controllers with [ApiController]
  • Marking APIs with [ApiRoute]
  • Scanning Controllers via reflection
  • Automatic API registration
  • Modular interface system

The final development experience will be as follows:

[ApiController]
public class DeviceController
{
    [ApiRoute("/api/device/list","GET")]
    public object List()
    {
        return DeviceManager.GetDevices();
    }
}
Enter fullscreen mode Exit fullscreen mode

There is no longer a need to manually register APIs.

When the server starts, it will automatically complete the following steps:

Scan Controllers
↓
Scan API methods
↓
Automatically register Routes
Enter fullscreen mode Exit fullscreen mode

I. Target Architecture

The final server structure is as follows:

MAUI App
   │
   └── PicoServer
          │
          ├── API Core
          │
          ├── Controller Scanner
          │
          └── Controllers
                 ├── SystemController
                 ├── DeviceController
                 ├── OrderController
                 └── StorageController
Enter fullscreen mode Exit fullscreen mode

Server startup process:

Scan Controllers
↓
Scan APIs
↓
Automatically register Routes
Enter fullscreen mode Exit fullscreen mode

II. Define the ApiController Attribute

First, define the Attribute for marking Controllers:

[AttributeUsage(AttributeTargets.Class)]
public class ApiControllerAttribute : Attribute
{
}
Enter fullscreen mode Exit fullscreen mode

Usage:

[ApiController]
public class DeviceController
{
}
Enter fullscreen mode Exit fullscreen mode

During scanning, the server will only load classes marked with [ApiController].

III. Define the API Route Attribute

Describe each API using an Attribute:

namespace MauiPicoAdmin;

[AttributeUsage(AttributeTargets.Method)]
public class ApiRouteAttribute : Attribute
{
    public string Path { get; }
    public string? Method { get; } 

    public ApiRouteAttribute(string path)
    {
        Path = path;
    }

    public ApiRouteAttribute(string path, string? method)
    {
        Path = path;
        Method = method;
    }
}
Enter fullscreen mode Exit fullscreen mode

Usage:

[ApiRoute("/api/system/info","GET")]
public object Info()
{
    return new
    {
        version = "1.0",
        time = DateTime.Now
    };
}
Enter fullscreen mode Exit fullscreen mode

IV. Controller Example

A complete Controller implementation:

[ApiController]
public class DeviceController
{
    [ApiRoute("/api/device/list","GET")]
    public object List()
    {
        return new
        {
            count = 5
        };
    }

    [ApiRoute("/api/device/start","POST")]
    public object Start()
    {
        return new
        {
            ok = true
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

Once the Controller is written, the API definition is complete.

V. Automatically Scan Controllers

Scan the assembly when the server starts:

var asm = Assembly.GetExecutingAssembly();

var controllers = asm.GetTypes()
    .Where(t => t.GetCustomAttribute<ApiControllerAttribute>() != null);
Enter fullscreen mode Exit fullscreen mode

This way, we can find all classes marked with [ApiController].

VI. Instantiate Controllers

Iterate through the discovered Controllers:

foreach (var type in controllers)
{
    var controller = Activator.CreateInstance(type);

    RegisterController(controller);
}
Enter fullscreen mode Exit fullscreen mode

VII. Scan API Methods

Scan the methods within each Controller:

void RegisterController(object controller)
{
    var methods = controller.GetType().GetMethods();

    foreach (var method in methods)
    {
        var route = method.GetCustomAttribute<ApiRouteAttribute>();

        if (route == null)
            continue;

        RegisterApi(route, controller, method);
    }
}
Enter fullscreen mode Exit fullscreen mode

This step finds all methods marked with [ApiRoute].

VIII. Automatically Register APIs

Unifiedly register interfaces in PicoServer using api.AddRoute():

The implementation code is as follows:

void RegisterApi(ApiRouteAttribute route, object controller, MethodInfo method)
{
    Func<HttpListenerRequest, HttpListenerResponse, Task> handler = (request, response) =>
    {
        var result = method.Invoke(controller, new object[] { request, response });
        return result as Task ?? Task.CompletedTask;
    };
    api.AddRoute(route.Path, handler, route.Method);
}
Enter fullscreen mode Exit fullscreen mode

This automatically converts Controller methods into API Routes.

IX. Complete Runtime Process

Execute the following method when the server starts:

ScanControllers();
Enter fullscreen mode Exit fullscreen mode

The complete process is as follows:

Scan the assembly
↓
Find [ApiController] classes
↓
Scan methods
↓
Find [ApiRoute] methods
↓
Call api.AddRoute()
↓
Complete API registration
Enter fullscreen mode Exit fullscreen mode

Eventually, all APIs are loaded automatically.

X. Final Development Experience

When developing APIs, you only need to write Controllers:

[ApiController]
public class OrderController
{
    [ApiRoute("/api/order/list","GET")]
    public object List()
    {
        return OrderService.GetOrders();
    }
}
Enter fullscreen mode Exit fullscreen mode

After the server starts, the API GET /api/order/list is registered automatically.

Developers no longer need to manually write any api.AddRoute(...) code, making the code extremely concise.

XI. Architectural Advantages

This API architecture brings the following benefits:

1. Automatic API Registration

Eliminates the need for a large number of api.AddRoute(...) code lines.

2. Modular Development

Each module has its own independent Controller:

  • SystemController
  • DeviceController
  • OrderController
  • StorageController
  • UserController

Resulting in a very clear structure.

3. Simple Expansion

Adding a new API only requires adding a method marked with [ApiRoute], with no need to modify server code.

4. Foundation for Plug-in Architecture

Although this article only scans the current assembly, it can be extended in the future to:

  • Scan external DLLs
  • Load Controllers from external assemblies

Thus implementing a true plug-in API system.

XII. Next Article Preview

In the next article, we will continue to upgrade the architecture with:

PicoServer + PWA Offline System

We will implement:

  • Browser offline operation
  • Service Worker
  • Local data caching
  • Offline Web Admin
  • MAUI Web Shell

Ultimately building a complete solution that integrates:

  • Offline Web App
  • Local API
  • MAUI Web Shell

A true local web application platform.

Top comments (0)