Files
Denso/srcs/RobotNet10/Commons/RobotNet10.CustomConfiguration/README.md
2026-07-03 16:31:37 +07:00

18 KiB

RobotNet10.CustomConfiguration

Thư viện quản lý cấu hình động cho ứng dụng RobotNet10, cho phép import/export, chỉnh sửa và quản lý các file cấu hình dạng JSON với hỗ trợ nhiều kiểu dữ liệu.

📋 Mục lục

Tính năng

  • Import/Export Config: Import và export các file cấu hình dạng JSON
  • Quản lý Config Files: Tạo, đọc, cập nhật, xóa các file cấu hình
  • Quản lý Variables: Thêm, sửa, xóa các biến trong config
  • Hỗ trợ nhiều kiểu dữ liệu: String, Int, Double, Bool, Object, Array, Enum
  • Validation: Kiểm tra tính hợp lệ của dữ liệu theo type và constraints
  • Tìm kiếm: Tìm kiếm config theo tên, loại
  • UI Component: Component Blazor sẵn có để quản lý config qua giao diện
  • Storage Manager: Tích hợp với RobotNet10.StorageManager (Local hoặc MinIO)

📁 Cấu trúc Project

RobotNet10.CustomConfiguration/
├── Controllers/
│   └── ConfigController.cs          # REST API Controller
├── DTOs/
│   ├── ConfigFileDto.cs
│   ├── ConfigFileMetadataDto.cs
│   ├── ConfigVariableDto.cs
│   └── Requests/
│       ├── CreateConfigRequest.cs
│       ├── UpdateConfigRequest.cs
│       └── UpdateVariableRequest.cs
├── Extensions/
│   └── ServiceCollectionExtensions.cs # DI Extension methods
├── Helpers/
│   ├── JsonConfigParser.cs          # Parse/Serialize JSON
│   └── VariableTypeConverter.cs    # Convert variable types
├── Models/
│   ├── ConfigFile.cs
│   ├── ConfigFileMetadata.cs
│   ├── ConfigVariable.cs
│   └── ConfigVariableType.cs
├── Services/
│   ├── IConfigService.cs
│   ├── ConfigService.cs
│   ├── ConfigService.Implementation.cs
│   └── ConfigService.Metadata.cs
└── Validators/
    └── ConfigValidator.cs           # Validation logic

🚀 Cài đặt và Cấu hình

1. Thêm Project Reference

Thêm reference vào project của bạn:

<ItemGroup>
  <ProjectReference Include="..\Commons\RobotNet10.CustomConfiguration\RobotNet10.CustomConfiguration.csproj" />
</ItemGroup>

2. Cấu hình Backend (ASP.NET Core)

Bước 1: Thêm using trong Program.cs

using RobotNet10.CustomConfiguration.Extensions;
using RobotNet10.StorageManager;

Bước 2: Đăng ký Services

Cách 1: Từ appsettings.json (Khuyến nghị)

// Trong Program.cs
builder.Services.AddCustomConfiguration(builder.Configuration, "StorageConfig");

Thêm vào appsettings.json:

{
  "StorageConfig": {
    "UsingLocal": true,
    "LocalFolder": "Configs",
    "Bucket": "",
    "RetryCount": 3,
    "MinioConfig": {
      "Endpoint": "localhost:9000",
      "User": "minioadmin",
      "Password": "minioadmin",
      "EnableSSL": false
    }
  }
}

Cách 2: Trực tiếp trong code

var storageConfig = new StorageConfig
{
    UsingLocal = true,
    LocalFolder = "Configs",
    Bucket = "",
    RetryCount = 3
};

builder.Services.AddCustomConfiguration(storageConfig);

Bước 3: Đảm bảo đã map Controllers

var app = builder.Build();

// ... middleware ...

app.MapControllers(); // Đảm bảo có dòng này

app.Run();

3. Cấu hình Frontend (Blazor)

Bước 1: Thêm Project Reference

<ItemGroup>
  <ProjectReference Include="..\Components\RobotNet10.CustomConfigurationEditor\RobotNet10.CustomConfigurationEditor.csproj" />
</ItemGroup>

Bước 2: Đăng ký Services trong Program.cs hoặc Client/Program.cs

using RobotNet10.CustomConfigurationEditor.Services.API;
using RobotNet10.CustomConfigurationEditor.Services.State;

// HttpClient (nếu chưa có)
builder.Services.AddScoped(sp => new HttpClient 
{ 
    BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) 
});

// MudBlazor (nếu chưa có)
builder.Services.AddMudServices();

// CustomConfiguration Services
builder.Services.AddScoped<ConfigApiService>();
builder.Services.AddScoped<ConfigManagerState>();

Bước 3: Copy JavaScript file

Copy file downloadFile.js từ RobotNet10.CustomConfigurationEditor/wwwroot/js/downloadFile.js vào wwwroot/js/ của project frontend.

Thêm vào index.html hoặc App.razor:

<script src="js/downloadFile.js"></script>

Bước 4: Thêm using trong _Imports.razor

@using RobotNet10.CustomConfigurationEditor.Components.ConfigManager

📖 Hướng dẫn sử dụng Backend

Sử dụng IConfigService

Inject IConfigService vào service hoặc controller của bạn:

public class MyService
{
    private readonly IConfigService _configService;
    
    public MyService(IConfigService configService)
    {
        _configService = configService;
    }
    
    public async Task<ConfigFile> GetMqttConfigAsync()
    {
        return await _configService.GetConfigByTypeAsync("MQTTBrokerConfig");
    }
}

Các phương thức chính

// Lấy tất cả configs (metadata)
var configs = await _configService.GetAllConfigsAsync();

// Lấy config theo ID
var config = await _configService.GetConfigByIdAsync(id);

// Lấy config theo ConfigType
var mqttConfig = await _configService.GetConfigByTypeAsync("MQTTBrokerConfig");

// Tạo config mới
var newConfig = await _configService.CreateConfigAsync(
    configType: "MyConfig",
    variables: variables,
    description: "My configuration"
);

// Cập nhật config
await _configService.UpdateConfigAsync(id, variables, description);

// Xóa config
await _configService.DeleteConfigAsync(id);

// Import từ file
using var stream = File.OpenRead("config.json");
var imported = await _configService.ImportConfigAsync(stream, "config.json", "MyConfig");

// Export ra file
var exportStream = await _configService.ExportConfigAsync(id);

// Cập nhật variable
await _configService.UpdateVariableAsync(id, "port", 8080);

// Thêm variable
await _configService.AddVariableAsync(id, newVariable);

// Xóa variable
await _configService.RemoveVariableAsync(id, "variableName");

🎨 Hướng dẫn sử dụng Frontend

Sử dụng Component

Tạo page mới hoặc thêm vào page hiện có:

@page "/config-manager"
@using RobotNet10.CustomConfigurationEditor.Components.ConfigManager

<ConfigManagerComponent />

Sử dụng ConfigManagerState

Inject ConfigManagerState vào component của bạn:

@inject ConfigManagerState State

<MudButton OnClick="LoadConfigs">Load Configs</MudButton>

@code {
    protected override async Task OnInitializedAsync()
    {
        await State.LoadConfigsAsync();
    }
    
    private async Task LoadConfigs()
    {
        await State.LoadConfigsAsync();
    }
}

Các phương thức State

// Load tất cả configs
await State.LoadConfigsAsync();

// Load với search query
await State.LoadConfigsAsync("MQTT");

// Load config theo ID
await State.LoadConfigByIdAsync(id);

// Load config theo ConfigType
await State.LoadConfigByTypeAsync("MQTTBrokerConfig");

// Select config
await State.SelectConfigAsync(configMetadata);

// Tạo config mới
var config = await State.CreateConfigAsync(
    configType: "MyConfig",
    variables: variables,
    description: "My config"
);

// Cập nhật config
await State.UpdateConfigAsync(variables, description);

// Xóa config
await State.DeleteConfigAsync(id);

// Import config
using var stream = file.OpenReadStream();
var imported = await State.ImportConfigAsync(stream, file.Name, "MyConfig");

// Export config
var stream = await State.ExportConfigAsync(id);

// Cập nhật variable
await State.UpdateVariableAsync("port", 8080);

// Thêm variable
await State.AddVariableAsync(newVariable);

// Xóa variable
await State.RemoveVariableAsync("variableName");

📄 Format JSON Config

Cấu trúc cơ bản

File config là một mảng JSON chứa các variable:

[
  {
    "name": "port",
    "type": "int",
    "value": 8080,
    "Min": 0,
    "Max": 65535,
    "Roles": ""
  },
  {
    "name": "host",
    "type": "string",
    "value": "localhost",
    "Roles": ""
  },
  {
    "name": "enableSSL",
    "type": "bool",
    "value": true,
    "Roles": ""
  }
]

Các kiểu dữ liệu hỗ trợ

1. String

{
  "name": "host",
  "type": "string",
  "value": "localhost",
  "Roles": ""
}

2. Int

{
  "name": "port",
  "type": "int",
  "value": 8080,
  "Min": 0,
  "Max": 65535,
  "Roles": ""
}

3. Double

{
  "name": "timeout",
  "type": "double",
  "value": 30.5,
  "Min": 0.0,
  "Max": 100.0,
  "Roles": ""
}

4. Bool

{
  "name": "enableSSL",
  "type": "bool",
  "value": true,
  "Roles": ""
}

5. Enum

{
  "name": "logLevel",
  "type": "enum",
  "value": "Info",
  "EnumValues": ["Debug", "Info", "Warning", "Error"],
  "Roles": ""
}

6. Object

{
  "name": "database",
  "type": "object",
  "value": {
    "host": "localhost",
    "port": 5432,
    "name": "mydb"
  },
  "Roles": ""
}

7. Array

{
  "name": "allowedIPs",
  "type": "array",
  "value": ["192.168.1.1", "192.168.1.2", "10.0.0.1"],
  "Roles": ""
}

Các thuộc tính

Thuộc tính Bắt buộc Mô tả
name Tên của variable (duy nhất trong config)
type Kiểu dữ liệu: string, int, double, bool, enum, object, array
value Giá trị của variable
Min Giá trị tối thiểu (cho intdouble)
Max Giá trị tối đa (cho intdouble)
EnumValues Danh sách giá trị cho phép (cho enum)
Roles Roles string (có thể để trống)

🔌 API Endpoints

Config File Management

GET /api/configs

Lấy tất cả configs (metadata only)

Query Parameters:

  • search (optional): Tìm kiếm theo tên hoặc ConfigType

Response: 200 OK

[
  {
    "id": "guid",
    "configType": "MQTTBrokerConfig",
    "createdAt": "2024-01-01T00:00:00Z",
    "updatedAt": "2024-01-01T00:00:00Z",
    "description": "MQTT Broker Configuration"
  }
]

GET /api/configs/{id}

Lấy config theo ID

Response: 200 OK

{
  "id": "guid",
  "configType": "MQTTBrokerConfig",
  "variables": [...],
  "createdAt": "2024-01-01T00:00:00Z",
  "updatedAt": "2024-01-01T00:00:00Z",
  "description": "MQTT Broker Configuration"
}

GET /api/configs/by-type/{configType}

Lấy config theo ConfigType

Response: 200 OK (same as GET by ID)

GET /api/configs/exists/{configType}

Kiểm tra ConfigType có tồn tại không

Response: 200 OK

true

POST /api/configs

Tạo config mới

Request Body:

{
  "configType": "MyConfig",
  "variables": [
    {
      "name": "port",
      "type": "int",
      "value": 8080
    }
  ],
  "description": "My configuration"
}

Response: 201 Created

PUT /api/configs/{id}

Cập nhật config

Request Body:

{
  "variables": [...],
  "description": "Updated description"
}

Response: 200 OK

DELETE /api/configs/{id}

Xóa config

Response: 204 No Content

Import/Export

POST /api/configs/import

Import config từ JSON file

Request: multipart/form-data

  • file: JSON file
  • configType: ConfigType name

Response: 200 OK

GET /api/configs/{id}/export

Export config ra JSON file

Response: 200 OK (application/json)

Variable Management

PUT /api/configs/{id}/variables/{variableName}

Cập nhật giá trị variable

Request Body:

{
  "variableName": "port",
  "value": 8080
}

Response: 200 OK

POST /api/configs/{id}/variables

Thêm variable mới

Request Body:

{
  "name": "newVariable",
  "type": "string",
  "value": "value"
}

Response: 200 OK

DELETE /api/configs/{id}/variables/{variableName}

Xóa variable

Response: 200 OK

💡 Ví dụ sử dụng

Ví dụ 1: Tạo MQTT Broker Config

var variables = new List<ConfigVariable>
{
    new ConfigVariable
    {
        Name = "host",
        Type = ConfigVariableType.String,
        Value = "localhost"
    },
    new ConfigVariable
    {
        Name = "port",
        Type = ConfigVariableType.Int,
        Value = 1883,
        Min = 0,
        Max = 65535
    },
    new ConfigVariable
    {
        Name = "enableSSL",
        Type = ConfigVariableType.Bool,
        Value = false
    }
};

var config = await _configService.CreateConfigAsync(
    configType: "MQTTBrokerConfig",
    variables: variables,
    description: "MQTT Broker Configuration"
);

Ví dụ 2: Import Config từ File

using var stream = File.OpenRead("mqtt-config.json");
var config = await _configService.ImportConfigAsync(
    stream: stream,
    fileName: "mqtt-config.json",
    configType: "MQTTBrokerConfig"
);

Ví dụ 3: Sử dụng Config trong Service

public class MqttService
{
    private readonly IConfigService _configService;
    
    public MqttService(IConfigService configService)
    {
        _configService = configService;
    }
    
    public async Task ConnectAsync()
    {
        var config = await _configService.GetConfigByTypeAsync("MQTTBrokerConfig");
        
        var host = config.Variables.First(v => v.Name == "host").Value?.ToString();
        var port = (int)config.Variables.First(v => v.Name == "port").Value!;
        
        // Connect to MQTT broker using host and port
    }
}

Ví dụ 4: Cập nhật Variable qua API

// C# HttpClient
var client = new HttpClient();
var request = new
{
    variableName = "port",
    value = 8883
};

var response = await client.PutAsJsonAsync(
    "https://api.example.com/api/configs/{id}/variables/port",
    request
);

Ví dụ 5: Frontend - Sử dụng Component

@page "/settings/config"
@using RobotNet10.CustomConfigurationEditor.Components.ConfigManager

<PageTitle>Configuration Manager</PageTitle>

<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="mt-4">
    <ConfigManagerComponent />
</MudContainer>

🔧 Troubleshooting

Lỗi: "ConfigType already exists"

Nguyên nhân: ConfigType đã tồn tại trong hệ thống.

Giải pháp:

  • Sử dụng ConfigType khác
  • Xóa config cũ trước khi tạo mới
  • Kiểm tra bằng ConfigTypeExistsAsync() trước khi tạo

Lỗi: "Invalid variable type"

Nguyên nhân: Type của variable không hợp lệ.

Giải pháp:

  • Kiểm tra type là một trong: string, int, double, bool, enum, object, array
  • Đảm bảo value phù hợp với type

Lỗi: "Value out of range"

Nguyên nhân: Giá trị vượt quá Min/Max.

Giải pháp:

  • Kiểm tra giá trị nằm trong khoảng Min và Max
  • Cập nhật Min/Max nếu cần

Lỗi: "Invalid JSON format"

Nguyên nhân: File JSON không đúng format.

Giải pháp:

  • Kiểm tra file là mảng JSON hợp lệ
  • Đảm bảo mỗi variable có name, type, value
  • Validate JSON trước khi import

Lỗi: "StorageManager not initialized"

Nguyên nhân: StorageConfig chưa được cấu hình.

Giải pháp:

  • Đảm bảo đã gọi AddCustomConfiguration() trong Program.cs
  • Kiểm tra StorageConfig trong appsettings.json

Frontend: Component không hiển thị

Nguyên nhân: Services chưa được đăng ký.

Giải pháp:

  • Kiểm tra đã đăng ký ConfigApiServiceConfigManagerState
  • Đảm bảo có HttpClient với BaseAddress
  • Kiểm tra đã có MudBlazor services

Frontend: Export không hoạt động

Nguyên nhân: JavaScript file chưa được thêm.

Giải pháp:

  • Copy downloadFile.js vào wwwroot/js/
  • Thêm script tag vào index.html hoặc App.razor

📝 Lưu ý

  1. ConfigType là duy nhất: Mỗi ConfigType chỉ có thể tồn tại một lần trong hệ thống
  2. Validation: Tất cả dữ liệu đều được validate trước khi lưu
  3. Storage: Config files được lưu trong configs/{ConfigType}.json trong StorageManager
  4. Metadata: Metadata được lưu trong configs/_metadata.json
  5. Thread Safety: Services được đăng ký là Scoped, phù hợp cho web applications

📚 Tài liệu tham khảo

🤝 Đóng góp

Nếu bạn phát hiện lỗi hoặc có đề xuất cải thiện, vui lòng tạo issue hoặc pull request.

📄 License

[Thêm thông tin license nếu có]