# 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](#tính-năng) - [Cấu trúc Project](#cấu-trúc-project) - [Cài đặt và Cấu hình](#cài-đặt-và-cấu-hình) - [Hướng dẫn sử dụng Backend](#hướng-dẫn-sử-dụng-backend) - [Hướng dẫn sử dụng Frontend](#hướng-dẫn-sử-dụng-frontend) - [Format JSON Config](#format-json-config) - [API Endpoints](#api-endpoints) - [Ví dụ sử dụng](#ví-dụ-sử-dụng) - [Troubleshooting](#troubleshooting) ## ✨ 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: ```xml ``` ### 2. Cấu hình Backend (ASP.NET Core) #### Bước 1: Thêm using trong `Program.cs` ```csharp using RobotNet10.CustomConfiguration.Extensions; using RobotNet10.StorageManager; ``` #### Bước 2: Đăng ký Services **Cách 1: Từ appsettings.json (Khuyến nghị)** ```csharp // Trong Program.cs builder.Services.AddCustomConfiguration(builder.Configuration, "StorageConfig"); ``` Thêm vào `appsettings.json`: ```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** ```csharp var storageConfig = new StorageConfig { UsingLocal = true, LocalFolder = "Configs", Bucket = "", RetryCount = 3 }; builder.Services.AddCustomConfiguration(storageConfig); ``` #### Bước 3: Đảm bảo đã map Controllers ```csharp 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 ```xml ``` #### Bước 2: Đăng ký Services trong `Program.cs` hoặc `Client/Program.cs` ```csharp 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(); builder.Services.AddScoped(); ``` #### 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`: ```html ``` #### Bước 4: Thêm using trong `_Imports.razor` ```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: ```csharp public class MyService { private readonly IConfigService _configService; public MyService(IConfigService configService) { _configService = configService; } public async Task GetMqttConfigAsync() { return await _configService.GetConfigByTypeAsync("MQTTBrokerConfig"); } } ``` ### Các phương thức chính ```csharp // 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ó: ```razor @page "/config-manager" @using RobotNet10.CustomConfigurationEditor.Components.ConfigManager ``` ### Sử dụng ConfigManagerState Inject `ConfigManagerState` vào component của bạn: ```razor @inject ConfigManagerState State Load Configs @code { protected override async Task OnInitializedAsync() { await State.LoadConfigsAsync(); } private async Task LoadConfigs() { await State.LoadConfigsAsync(); } } ``` ### Các phương thức State ```csharp // 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: ```json [ { "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 ```json { "name": "host", "type": "string", "value": "localhost", "Roles": "" } ``` #### 2. Int ```json { "name": "port", "type": "int", "value": 8080, "Min": 0, "Max": 65535, "Roles": "" } ``` #### 3. Double ```json { "name": "timeout", "type": "double", "value": 30.5, "Min": 0.0, "Max": 100.0, "Roles": "" } ``` #### 4. Bool ```json { "name": "enableSSL", "type": "bool", "value": true, "Roles": "" } ``` #### 5. Enum ```json { "name": "logLevel", "type": "enum", "value": "Info", "EnumValues": ["Debug", "Info", "Warning", "Error"], "Roles": "" } ``` #### 6. Object ```json { "name": "database", "type": "object", "value": { "host": "localhost", "port": 5432, "name": "mydb" }, "Roles": "" } ``` #### 7. Array ```json { "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 `int` và `double`) | | `Max` | ❌ | Giá trị tối đa (cho `int` và `double`) | | `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` ```json [ { "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` ```json { "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` ```json true ``` #### POST `/api/configs` Tạo config mới **Request Body:** ```json { "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:** ```json { "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:** ```json { "variableName": "port", "value": 8080 } ``` **Response:** `200 OK` #### POST `/api/configs/{id}/variables` Thêm variable mới **Request Body:** ```json { "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 ```csharp var variables = new List { 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 ```csharp 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 ```csharp 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 ```csharp // 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 ```razor @page "/settings/config" @using RobotNet10.CustomConfigurationEditor.Components.ConfigManager Configuration Manager ``` ## 🔧 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ý `ConfigApiService` và `ConfigManagerState` - Đả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 - [RobotNet10.StorageManager Documentation](../RobotNet10.StorageManager/README.md) - [MudBlazor Documentation](https://mudblazor.com/) - [ASP.NET Core Documentation](https://docs.microsoft.com/aspnet/core) ## 🤝 Đó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ó]