Initial commit
This commit is contained in:
785
srcs/RobotNet10/Commons/RobotNet10.CustomConfiguration/README.md
Normal file
785
srcs/RobotNet10/Commons/RobotNet10.CustomConfiguration/README.md
Normal file
@@ -0,0 +1,785 @@
|
||||
# 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
|
||||
<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`
|
||||
|
||||
```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
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Components\RobotNet10.CustomConfigurationEditor\RobotNet10.CustomConfigurationEditor.csproj" />
|
||||
</ItemGroup>
|
||||
```
|
||||
|
||||
#### 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<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`:
|
||||
|
||||
```html
|
||||
<script src="js/downloadFile.js"></script>
|
||||
```
|
||||
|
||||
#### 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<ConfigFile> 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
|
||||
|
||||
<ConfigManagerComponent />
|
||||
```
|
||||
|
||||
### Sử dụng ConfigManagerState
|
||||
|
||||
Inject `ConfigManagerState` vào component của bạn:
|
||||
|
||||
```razor
|
||||
@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
|
||||
|
||||
```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<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
|
||||
|
||||
```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
|
||||
|
||||
<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ý `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ó]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user