A:整体并简化代码
This commit is contained in:
1 parent
2c83fc72e4
commit
2563288afe
26 files changed
+888
-565
No files matched your search
@@ -54,19 +54,20 @@ dotnet clean Sharp.sln
|
|||||||
|
|
||||||
```
|
```
|
||||||
src/Sharp/ # All source projects
|
src/Sharp/ # All source projects
|
||||||
├── Common/ # Core foundation (Result<T>, Global container, utilities)
|
├── Common/ # Core foundation (Result<T>, Global container, utilities, SystemConfig)
|
||||||
├── Config/ # Multi-format configuration with hot-reload
|
├── Config/ # Multi-format configuration with hot-reload
|
||||||
├── Sharp.Infrastructure/ # Infrastructure abstractions
|
|
||||||
├── Wpf/ # WPF UI toolkit (MVVM, dialogs, converters)
|
├── Wpf/ # WPF UI toolkit (MVVM, dialogs, converters)
|
||||||
├── Data/ # EF Core wrapper with repository pattern
|
├── Data/ # EF Core wrapper with repository pattern
|
||||||
├── Repository/ # Repository implementations
|
|
||||||
├── Log/ # Serilog-based structured logging
|
├── Log/ # Serilog-based structured logging
|
||||||
|
├── Cache/ # Memory cache (planned)
|
||||||
|
├── EventBus/ # Event pub/sub (planned)
|
||||||
├── NetClient/ # HTTP client with Polly resilience
|
├── NetClient/ # HTTP client with Polly resilience
|
||||||
├── NetServer/ # Lightweight HTTP server with middleware
|
├── NetServer/ # Lightweight HTTP server with middleware
|
||||||
├── Ports/ # Serial port abstraction (RS232/RS485)
|
├── Ports/ # Serial port abstraction (RS232/RS485)
|
||||||
├── Plc/ # PLC abstraction interface
|
├── Plc/ # PLC abstraction interface
|
||||||
├── Plc.Siemens/ # Siemens S7 PLC implementation (S7.NET+)
|
├── Plc.Siemens/ # Siemens S7 PLC implementation (S7.NET+)
|
||||||
├── EventBus/ # Event pub/sub (planned)
|
├── Process/ # Process execution
|
||||||
|
├── Python/ # Python script execution
|
||||||
├── Client/ # WPF demo application
|
├── Client/ # WPF demo application
|
||||||
└── Server/ # WPF server example
|
└── Server/ # WPF server example
|
||||||
|
|
||||||
@@ -77,6 +78,8 @@ test/ # MSTest test projects
|
|||||||
├── Log.Test/
|
├── Log.Test/
|
||||||
├── NetClient.Test/
|
├── NetClient.Test/
|
||||||
└── NetServer.Test/
|
└── NetServer.Test/
|
||||||
|
|
||||||
|
appsettings.template.json # 完整的配置模板文件
|
||||||
```
|
```
|
||||||
|
|
||||||
### Key Architectural Patterns
|
### Key Architectural Patterns
|
||||||
|
|||||||
@@ -0,0 +1,486 @@
|
|||||||
|
# Sharp-Basic 配置指南
|
||||||
|
|
||||||
|
本文档说明 Sharp-Basic 框架的配置约定和最佳实践。
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [配置文件模板](#配置文件模板)
|
||||||
|
- [约定配置节名称](#约定配置节名称)
|
||||||
|
- [环境变量覆盖](#环境变量覆盖)
|
||||||
|
- [模块配置详解](#模块配置详解)
|
||||||
|
- [最佳实践](#最佳实践)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 配置文件模板
|
||||||
|
|
||||||
|
Sharp-Basic 提供了完整的配置文件模板:**`appsettings.template.json`**
|
||||||
|
|
||||||
|
### 使用方法
|
||||||
|
|
||||||
|
1. **复制模板文件**
|
||||||
|
```bash
|
||||||
|
cp appsettings.template.json appsettings.json
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **根据项目需要选择性保留配置**
|
||||||
|
- 只使用数据库?保留 `Database` 节
|
||||||
|
- 需要PLC通信?保留 `Plc:Siemens` 节
|
||||||
|
- 不需要的配置可以删除
|
||||||
|
|
||||||
|
3. **修改配置值**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Database": {
|
||||||
|
"Provider": "SqlServer",
|
||||||
|
"ConnectionString": "你的数据库连接字符串"
|
||||||
|
},
|
||||||
|
"Plc": {
|
||||||
|
"Siemens": {
|
||||||
|
"IpAddress": "你的PLC IP地址"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 约定配置节名称
|
||||||
|
|
||||||
|
Sharp-Basic 遵循 **"约定优于配置"** 原则,每个模块都有固定的配置节名称:
|
||||||
|
|
||||||
|
### 核心模块
|
||||||
|
|
||||||
|
| 模块 | 配置节名称 | 说明 | 必填字段 |
|
||||||
|
|------|------------|------|----------|
|
||||||
|
| **System** | `System` | 系统级HTTP配置 | `HTTPIp`, `HttpPort` |
|
||||||
|
| **Database** | `Database` | 数据库连接配置 | `Provider`, `ConnectionString` |
|
||||||
|
| **Logging** | `Logging` | 日志级别配置 | `LogLevel` |
|
||||||
|
| **SharpLog** | `SharpLog` | Sharp日志扩展 | 无(全部可选) |
|
||||||
|
|
||||||
|
### 网络模块
|
||||||
|
|
||||||
|
| 模块 | 配置节名称 | 说明 | 必填字段 |
|
||||||
|
|------|------------|------|----------|
|
||||||
|
| **NetClient** | `NetClient` | HTTP客户端配置 | 无(可使用System默认值) |
|
||||||
|
| **NetServer** | `NetServer` | HTTP服务端配置 | 无(可使用System默认值) |
|
||||||
|
|
||||||
|
### IoT模块
|
||||||
|
|
||||||
|
| 模块 | 配置节名称 | 说明 | 必填字段 |
|
||||||
|
|------|------------|------|----------|
|
||||||
|
| **Plc.Siemens** | `Plc:Siemens` | 西门子PLC配置 | `IpAddress`, `CpuType` |
|
||||||
|
| **SerialPort** | `SerialPort` | 串口通信配置 | `PortName`, `BaudRate` |
|
||||||
|
|
||||||
|
### 工具模块
|
||||||
|
|
||||||
|
| 模块 | 配置节名称 | 说明 | 必填字段 |
|
||||||
|
|------|------------|------|----------|
|
||||||
|
| **Process** | `Process` | 进程执行配置 | 无(全部可选) |
|
||||||
|
| **Python** | `Python` | Python脚本配置 | 无(全部可选) |
|
||||||
|
| **Cache** | `Cache` | 缓存配置 | 无(全部可选) |
|
||||||
|
| **EventBus** | `EventBus` | 事件总线配置 | 无(全部可选) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 环境变量覆盖
|
||||||
|
|
||||||
|
所有配置都可以通过环境变量覆盖,格式:`SHARP__{节名}__{键名}`
|
||||||
|
|
||||||
|
### 覆盖规则
|
||||||
|
|
||||||
|
- 使用双下划线 `__` 分隔层级
|
||||||
|
- 所有字母必须大写(Windows不区分大小写,Linux区分)
|
||||||
|
- 冒号 `:` 用双下划线 `__` 替代
|
||||||
|
|
||||||
|
### 示例
|
||||||
|
|
||||||
|
#### 覆盖数据库配置
|
||||||
|
```bash
|
||||||
|
# Windows (PowerShell)
|
||||||
|
$env:SHARP__Database__Provider="Sqlite"
|
||||||
|
$env:SHARP__Database__ConnectionString="Data Source=test.db"
|
||||||
|
|
||||||
|
# Linux/macOS
|
||||||
|
export SHARP__Database__Provider=Sqlite
|
||||||
|
export SHARP__Database__ConnectionString="Data Source=test.db"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 覆盖PLC配置
|
||||||
|
```bash
|
||||||
|
# Windows (PowerShell)
|
||||||
|
$env:SHARP__Plc__Siemens__IpAddress="192.168.1.200"
|
||||||
|
$env:SHARP__Plc__Siemens__CpuType="S71500"
|
||||||
|
|
||||||
|
# Linux/macOS
|
||||||
|
export SHARP__Plc__Siemens__IpAddress=192.168.1.200
|
||||||
|
export SHARP__Plc__Siemens__CpuType=S71500
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 覆盖System配置
|
||||||
|
```bash
|
||||||
|
# Windows (PowerShell)
|
||||||
|
$env:SHARP__System__HttpPort="9090"
|
||||||
|
|
||||||
|
# Linux/macOS
|
||||||
|
export SHARP__System__HttpPort=9090
|
||||||
|
```
|
||||||
|
|
||||||
|
### 优先级
|
||||||
|
|
||||||
|
配置优先级从高到低:
|
||||||
|
1. **环境变量** - 最高优先级
|
||||||
|
2. **appsettings.{Environment}.json** - 环境特定配置
|
||||||
|
3. **appsettings.json** - 默认配置
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 模块配置详解
|
||||||
|
|
||||||
|
### 1. 数据库配置 (Database)
|
||||||
|
|
||||||
|
#### 最简配置
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Database": {
|
||||||
|
"Provider": "Sqlite",
|
||||||
|
"ConnectionString": "Data Source=app.db"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 代码中使用
|
||||||
|
```csharp
|
||||||
|
var config = ConfigBuilder.CreateDefault().Configuration;
|
||||||
|
services.AddSharpDatabase<AppDbContext>(config); // 自动读取 Database 节
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 支持的数据库提供程序
|
||||||
|
- `SqlServer` - Microsoft SQL Server
|
||||||
|
- `Sqlite` - SQLite
|
||||||
|
- `PostgreSQL` - PostgreSQL
|
||||||
|
- `MySql` - MySQL/MariaDB
|
||||||
|
- `InMemory` - 内存数据库(仅用于测试)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. PLC配置 (Plc:Siemens)
|
||||||
|
|
||||||
|
#### 最简配置
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Plc": {
|
||||||
|
"Siemens": {
|
||||||
|
"IpAddress": "192.168.1.100",
|
||||||
|
"CpuType": "S71200"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 代码中使用
|
||||||
|
```csharp
|
||||||
|
var config = ConfigBuilder.CreateDefault().Configuration;
|
||||||
|
services.AddSiemensPlc(config.GetSection("Plc:Siemens"));
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 支持的CPU类型
|
||||||
|
- `S71200` - S7-1200 系列
|
||||||
|
- `S71500` - S7-1500 系列
|
||||||
|
- `S7300` - S7-300 系列
|
||||||
|
- `S7400` - S7-400 系列
|
||||||
|
- `S7200` - S7-200 系列
|
||||||
|
- `S7200Smart` - S7-200 Smart 系列
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. 日志配置 (Logging & SharpLog)
|
||||||
|
|
||||||
|
#### 最简配置
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SharpLog": {
|
||||||
|
"LogFilePath": "logs/app-.log",
|
||||||
|
"RollingInterval": "Day"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 代码中使用
|
||||||
|
```csharp
|
||||||
|
services.AddLogging(b => b.AddSharpLog()); // 自动读取 SharpLog 节
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. HTTP配置 (System, NetClient, NetServer)
|
||||||
|
|
||||||
|
#### System配置(共享默认值)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"System": {
|
||||||
|
"HTTPIp": "127.0.0.1",
|
||||||
|
"HttpPort": 8080,
|
||||||
|
"TimeoutSeconds": 30,
|
||||||
|
"Scheme": "http"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### NetClient配置(可选,留空则使用System默认值)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"NetClient": {
|
||||||
|
"BaseAddress": "http://api.example.com",
|
||||||
|
"Timeout": "00:00:30",
|
||||||
|
"EnableLogging": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### NetServer配置(可选,留空则使用System默认值)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"NetServer": {
|
||||||
|
"ListenUrls": [
|
||||||
|
"http://localhost:8080/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
### 1. 按需配置
|
||||||
|
|
||||||
|
**只保留需要的配置节**,不要保留所有模板内容:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
// ❌ 不好:保留了不使用的配置
|
||||||
|
"Database": { ... },
|
||||||
|
"Plc": { ... },
|
||||||
|
"SerialPort": { ... },
|
||||||
|
"Python": { ... }
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// ✅ 好:只保留需要的配置
|
||||||
|
"Database": { ... },
|
||||||
|
"Logging": { ... }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 使用环境特定配置
|
||||||
|
|
||||||
|
为不同环境创建不同的配置文件:
|
||||||
|
|
||||||
|
```
|
||||||
|
appsettings.json # 默认配置
|
||||||
|
appsettings.Development.json # 开发环境
|
||||||
|
appsettings.Production.json # 生产环境
|
||||||
|
appsettings.Testing.json # 测试环境
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 敏感信息使用环境变量
|
||||||
|
|
||||||
|
**不要在配置文件中存储敏感信息**(密码、密钥等):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ✅ 好:使用环境变量
|
||||||
|
export SHARP__Database__ConnectionString="Server=prod;User=sa;Password=SecretPass123"
|
||||||
|
export SHARP__Plc__Siemens__IpAddress="192.168.1.100"
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
// ❌ 不好:敏感信息写在配置文件
|
||||||
|
{
|
||||||
|
"Database": {
|
||||||
|
"ConnectionString": "Server=prod;User=sa;Password=SecretPass123"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 添加注释说明
|
||||||
|
|
||||||
|
在配置文件中添加注释(JSON5格式,或删除注释后部署):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
// 数据库配置 - 生产环境使用SQL Server
|
||||||
|
"Database": {
|
||||||
|
"Provider": "SqlServer",
|
||||||
|
"ConnectionString": "Server=.;Database=MyApp;..."
|
||||||
|
},
|
||||||
|
|
||||||
|
// PLC配置 - 车间1号PLC
|
||||||
|
"Plc": {
|
||||||
|
"Siemens": {
|
||||||
|
"IpAddress": "192.168.1.100", // 车间1号PLC
|
||||||
|
"CpuType": "S71200"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 配置验证
|
||||||
|
|
||||||
|
Sharp-Basic 会在启动时验证必填配置项:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// ✅ 好:配置缺失时会抛出清晰的异常
|
||||||
|
services.AddSharpDatabase<AppDbContext>(config);
|
||||||
|
// 异常:未找到数据库连接字符串配置: Database:ConnectionString
|
||||||
|
|
||||||
|
services.AddSiemensPlc(config.GetSection("Plc:Siemens"));
|
||||||
|
// 异常:未配置PLC IP地址
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速参考
|
||||||
|
|
||||||
|
### 典型WPF应用配置
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"System": {
|
||||||
|
"HTTPIp": "127.0.0.1",
|
||||||
|
"HttpPort": 8080
|
||||||
|
},
|
||||||
|
"Database": {
|
||||||
|
"Provider": "Sqlite",
|
||||||
|
"ConnectionString": "Data Source=app.db"
|
||||||
|
},
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SharpLog": {
|
||||||
|
"LogFilePath": "logs/app-.log",
|
||||||
|
"RollingInterval": "Day"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 工业IoT应用配置
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"System": {
|
||||||
|
"HTTPIp": "0.0.0.0",
|
||||||
|
"HttpPort": 8080
|
||||||
|
},
|
||||||
|
"Database": {
|
||||||
|
"Provider": "SqlServer",
|
||||||
|
"ConnectionString": "Server=.;Database=ScadaDB;Trusted_Connection=True;"
|
||||||
|
},
|
||||||
|
"Plc": {
|
||||||
|
"Siemens": {
|
||||||
|
"IpAddress": "192.168.1.100",
|
||||||
|
"CpuType": "S71200",
|
||||||
|
"MonitorInterval": 500,
|
||||||
|
"AutoReconnect": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SerialPort": {
|
||||||
|
"PortName": "COM1",
|
||||||
|
"BaudRate": 9600
|
||||||
|
},
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Plc.Siemens": "Debug"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Web服务应用配置
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"System": {
|
||||||
|
"HTTPIp": "0.0.0.0",
|
||||||
|
"HttpPort": 5000,
|
||||||
|
"Scheme": "https"
|
||||||
|
},
|
||||||
|
"Database": {
|
||||||
|
"Provider": "PostgreSQL",
|
||||||
|
"ConnectionString": "Host=localhost;Database=myapi;Username=postgres;Password=***"
|
||||||
|
},
|
||||||
|
"NetServer": {
|
||||||
|
"ListenUrls": [
|
||||||
|
"https://0.0.0.0:5000/",
|
||||||
|
"http://0.0.0.0:5001/"
|
||||||
|
],
|
||||||
|
"ShowDetailedErrors": false
|
||||||
|
},
|
||||||
|
"Cache": {
|
||||||
|
"DefaultExpirationSeconds": 300,
|
||||||
|
"SizeLimit": 10000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关文档
|
||||||
|
|
||||||
|
- [appsettings.template.json](appsettings.template.json) - 完整配置模板
|
||||||
|
- [Config模块README](src/Sharp/Config/README.md) - 配置管理详解
|
||||||
|
- [Data模块README](src/Sharp/Data/README.md) - 数据库配置详解
|
||||||
|
- [Plc.Siemens模块README](src/Sharp/Plc.Siemens/README.md) - PLC配置详解
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 故障排查
|
||||||
|
|
||||||
|
### 问题:找不到配置节
|
||||||
|
|
||||||
|
**错误信息**:
|
||||||
|
```
|
||||||
|
未找到数据库连接字符串配置: Database:ConnectionString
|
||||||
|
```
|
||||||
|
|
||||||
|
**解决方法**:
|
||||||
|
1. 检查配置文件名是否为 `appsettings.json`
|
||||||
|
2. 检查配置节名称是否正确(区分大小写)
|
||||||
|
3. 检查配置文件是否在项目根目录
|
||||||
|
4. 检查配置文件的 "复制到输出目录" 设置
|
||||||
|
|
||||||
|
### 问题:环境变量不生效
|
||||||
|
|
||||||
|
**原因**:环境变量格式错误
|
||||||
|
|
||||||
|
**正确格式**:
|
||||||
|
```bash
|
||||||
|
# ✅ 正确:双下划线分隔
|
||||||
|
SHARP__Database__Provider=Sqlite
|
||||||
|
|
||||||
|
# ❌ 错误:单下划线
|
||||||
|
SHARP_Database_Provider=Sqlite
|
||||||
|
|
||||||
|
# ❌ 错误:使用冒号
|
||||||
|
SHARP:Database:Provider=Sqlite
|
||||||
|
```
|
||||||
|
|
||||||
|
### 问题:配置被覆盖
|
||||||
|
|
||||||
|
**检查优先级**:
|
||||||
|
1. 先检查环境变量
|
||||||
|
2. 再检查 appsettings.{Environment}.json
|
||||||
|
3. 最后检查 appsettings.json
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**版本**: 1.0.0
|
||||||
|
**更新日期**: 2025-12-22
|
||||||
@@ -0,0 +1,361 @@
|
|||||||
|
{
|
||||||
|
// ========================================
|
||||||
|
// Sharp-Basic 框架配置模板
|
||||||
|
//
|
||||||
|
// 这是一个完整的配置文件模板,包含了所有Sharp模块的配置示例
|
||||||
|
// 使用时可以根据项目需要选择性保留相关配置节
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 系统配置 (System)
|
||||||
|
// 约定配置节名称:System
|
||||||
|
// 用于:NetClient、NetServer 的默认HTTP配置
|
||||||
|
// ========================================
|
||||||
|
"System": {
|
||||||
|
// HTTP服务监听IP地址
|
||||||
|
// 支持:IP地址、localhost、域名
|
||||||
|
"HTTPIp": "127.0.0.1",
|
||||||
|
|
||||||
|
// HTTP服务监听端口
|
||||||
|
// 范围:1-65535
|
||||||
|
"HttpPort": 8080,
|
||||||
|
|
||||||
|
// HTTP请求超时时间(秒)
|
||||||
|
// 范围:1-600
|
||||||
|
"TimeoutSeconds": 30,
|
||||||
|
|
||||||
|
// HTTP协议
|
||||||
|
// 可选值:http、https
|
||||||
|
"Scheme": "http"
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 数据库配置 (Database)
|
||||||
|
// 约定配置节名称:Database
|
||||||
|
// 用于:Data 模块 - AddSharpDatabase<TContext>(configuration)
|
||||||
|
// ========================================
|
||||||
|
"Database": {
|
||||||
|
// 数据库提供程序
|
||||||
|
// 可选值:SqlServer、Sqlite、PostgreSQL、MySql、InMemory
|
||||||
|
"Provider": "SqlServer",
|
||||||
|
|
||||||
|
// 数据库连接字符串
|
||||||
|
// SqlServer示例:Server=.;Database=MyApp;Trusted_Connection=True;TrustServerCertificate=True;
|
||||||
|
// Sqlite示例:Data Source=app.db
|
||||||
|
// PostgreSQL示例:Host=localhost;Database=myapp;Username=postgres;Password=123456
|
||||||
|
// MySql示例:server=localhost;database=myapp;user=root;password=123456
|
||||||
|
"ConnectionString": "Server=.;Database=MyApp;Trusted_Connection=True;TrustServerCertificate=True;"
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 日志配置 (Logging)
|
||||||
|
// 约定配置节名称:Logging
|
||||||
|
// 用于:Log 模块 - AddLogging(b => b.AddSharpLog())
|
||||||
|
// ========================================
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Sharp日志扩展配置
|
||||||
|
"SharpLog": {
|
||||||
|
// 日志文件路径(相对或绝对路径)
|
||||||
|
"LogFilePath": "logs/app-.log",
|
||||||
|
|
||||||
|
// 日志滚动间隔
|
||||||
|
// 可选值:Infinite、Year、Month、Day、Hour、Minute
|
||||||
|
"RollingInterval": "Day",
|
||||||
|
|
||||||
|
// 单个日志文件最大大小(字节)
|
||||||
|
// null 表示不限制
|
||||||
|
"FileSizeLimitBytes": 10485760,
|
||||||
|
|
||||||
|
// 保留的日志文件数量
|
||||||
|
// null 表示不限制
|
||||||
|
"RetainedFileCountLimit": 31,
|
||||||
|
|
||||||
|
// 是否输出到控制台
|
||||||
|
"EnableConsole": true,
|
||||||
|
|
||||||
|
// 是否输出到文件
|
||||||
|
"EnableFile": true,
|
||||||
|
|
||||||
|
// 是否启用结构化日志(JSON格式)
|
||||||
|
"EnableStructuredLog": false
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// HTTP客户端配置 (NetClient)
|
||||||
|
// 约定配置节名称:NetClient
|
||||||
|
// 用于:NetClient 模块 - AddNetClient(configuration.GetSection("NetClient"))
|
||||||
|
// ========================================
|
||||||
|
"NetClient": {
|
||||||
|
// 基础地址(留空则使用System配置)
|
||||||
|
"BaseAddress": "http://localhost:8080",
|
||||||
|
|
||||||
|
// 请求超时时间
|
||||||
|
"Timeout": "00:00:30",
|
||||||
|
|
||||||
|
// 是否启用日志
|
||||||
|
"EnableLogging": true,
|
||||||
|
|
||||||
|
// 是否包含关联ID
|
||||||
|
"IncludeCorrelationId": true,
|
||||||
|
|
||||||
|
// 关联ID请求头名称
|
||||||
|
"CorrelationIdHeaderName": "X-Correlation-ID",
|
||||||
|
|
||||||
|
// 是否使用Bearer Token认证
|
||||||
|
"UseBearerToken": false,
|
||||||
|
|
||||||
|
// 重试配置
|
||||||
|
"Retry": {
|
||||||
|
// 是否启用重试
|
||||||
|
"Enabled": true,
|
||||||
|
|
||||||
|
// 最大重试次数
|
||||||
|
"MaxRetries": 3,
|
||||||
|
|
||||||
|
// 重试延迟(秒)
|
||||||
|
"DelaySeconds": 2
|
||||||
|
},
|
||||||
|
|
||||||
|
// 默认请求头
|
||||||
|
"DefaultRequestHeaders": {
|
||||||
|
"User-Agent": "Sharp-NetClient/1.0",
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// HTTP服务端配置 (NetServer)
|
||||||
|
// 约定配置节名称:NetServer
|
||||||
|
// 用于:NetServer 模块 - AddNetServer(configManager)
|
||||||
|
// ========================================
|
||||||
|
"NetServer": {
|
||||||
|
// 监听URL列表(留空则使用System配置)
|
||||||
|
"ListenUrls": [
|
||||||
|
"http://localhost:8080/",
|
||||||
|
"http://0.0.0.0:8080/"
|
||||||
|
],
|
||||||
|
|
||||||
|
// 是否启用详细错误信息
|
||||||
|
"ShowDetailedErrors": true,
|
||||||
|
|
||||||
|
// 请求正文最大大小(字节)
|
||||||
|
"MaxRequestBodySize": 30000000,
|
||||||
|
|
||||||
|
// 请求超时时间
|
||||||
|
"RequestTimeout": "00:05:00"
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// PLC配置 - 西门子 (Plc:Siemens)
|
||||||
|
// 约定配置节名称:Plc:Siemens
|
||||||
|
// 用于:Plc.Siemens 模块 - AddSiemensPlc(configuration.GetSection("Plc:Siemens"))
|
||||||
|
// ========================================
|
||||||
|
"Plc": {
|
||||||
|
"Siemens": {
|
||||||
|
// PLC IP地址
|
||||||
|
"IpAddress": "192.168.1.100",
|
||||||
|
|
||||||
|
// CPU类型
|
||||||
|
// 可选值:S71200、S71500、S7300、S7400、S7200、S7200Smart
|
||||||
|
"CpuType": "S71200",
|
||||||
|
|
||||||
|
// 机架号(S7-300/400)
|
||||||
|
"Rack": 0,
|
||||||
|
|
||||||
|
// 插槽号(S7-300/400)
|
||||||
|
"Slot": 1,
|
||||||
|
|
||||||
|
// 端口号
|
||||||
|
"Port": 102,
|
||||||
|
|
||||||
|
// 连接超时时间(毫秒)
|
||||||
|
"ConnectTimeout": 5000,
|
||||||
|
|
||||||
|
// 读写超时时间(毫秒)
|
||||||
|
"ReadWriteTimeout": 3000,
|
||||||
|
|
||||||
|
// 监控轮询间隔(毫秒)
|
||||||
|
"MonitorInterval": 500,
|
||||||
|
|
||||||
|
// 是否自动重连
|
||||||
|
"AutoReconnect": true,
|
||||||
|
|
||||||
|
// 重连间隔(毫秒)
|
||||||
|
"ReconnectInterval": 5000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 串口配置 (SerialPort)
|
||||||
|
// 约定配置节名称:SerialPort
|
||||||
|
// 用于:Ports 模块 - AddSerialPortService()
|
||||||
|
// ========================================
|
||||||
|
"SerialPort": {
|
||||||
|
// 端口名称(如 COM1、/dev/ttyUSB0)
|
||||||
|
"PortName": "COM1",
|
||||||
|
|
||||||
|
// 波特率
|
||||||
|
// 常用值:9600、19200、38400、57600、115200
|
||||||
|
"BaudRate": 9600,
|
||||||
|
|
||||||
|
// 数据位
|
||||||
|
// 可选值:5、6、7、8
|
||||||
|
"DataBits": 8,
|
||||||
|
|
||||||
|
// 停止位
|
||||||
|
// 可选值:None、One、Two、OnePointFive
|
||||||
|
"StopBits": "One",
|
||||||
|
|
||||||
|
// 校验位
|
||||||
|
// 可选值:None、Odd、Even、Mark、Space
|
||||||
|
"Parity": "None",
|
||||||
|
|
||||||
|
// 读取超时时间(毫秒)
|
||||||
|
// -1 表示无限等待
|
||||||
|
"ReadTimeout": 1000,
|
||||||
|
|
||||||
|
// 写入超时时间(毫秒)
|
||||||
|
// -1 表示无限等待
|
||||||
|
"WriteTimeout": 1000,
|
||||||
|
|
||||||
|
// 接收缓冲区大小(字节)
|
||||||
|
"ReadBufferSize": 4096,
|
||||||
|
|
||||||
|
// 发送缓冲区大小(字节)
|
||||||
|
"WriteBufferSize": 2048
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 进程执行配置 (Process)
|
||||||
|
// 约定配置节名称:Process
|
||||||
|
// 用于:Process 模块 - AddSharpProcess()
|
||||||
|
// ========================================
|
||||||
|
"Process": {
|
||||||
|
// 默认工作目录
|
||||||
|
"WorkingDirectory": "",
|
||||||
|
|
||||||
|
// 默认超时时间(毫秒)
|
||||||
|
// -1 表示无限等待
|
||||||
|
"DefaultTimeout": 30000,
|
||||||
|
|
||||||
|
// 是否重定向标准输出
|
||||||
|
"RedirectStandardOutput": true,
|
||||||
|
|
||||||
|
// 是否重定向标准错误
|
||||||
|
"RedirectStandardError": true,
|
||||||
|
|
||||||
|
// 是否使用Shell执行
|
||||||
|
"UseShellExecute": false,
|
||||||
|
|
||||||
|
// 是否创建窗口
|
||||||
|
"CreateNoWindow": true
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// Python配置 (Python)
|
||||||
|
// 约定配置节名称:Python
|
||||||
|
// 用于:Python 模块 - AddSharpPython()
|
||||||
|
// ========================================
|
||||||
|
"Python": {
|
||||||
|
// Python解释器路径
|
||||||
|
// 留空则自动查找系统PATH中的python
|
||||||
|
"PythonPath": "",
|
||||||
|
|
||||||
|
// Python脚本根目录
|
||||||
|
"ScriptDirectory": "scripts",
|
||||||
|
|
||||||
|
// 默认超时时间(毫秒)
|
||||||
|
"DefaultTimeout": 60000,
|
||||||
|
|
||||||
|
// 是否启用虚拟环境
|
||||||
|
"UseVirtualEnv": false,
|
||||||
|
|
||||||
|
// 虚拟环境路径
|
||||||
|
"VirtualEnvPath": ""
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 缓存配置 (Cache)
|
||||||
|
// 约定配置节名称:Cache
|
||||||
|
// 用于:Cache 模块 - AddSharpCache()
|
||||||
|
// ========================================
|
||||||
|
"Cache": {
|
||||||
|
// 默认过期时间(秒)
|
||||||
|
"DefaultExpirationSeconds": 600,
|
||||||
|
|
||||||
|
// 缓存大小限制(条目数)
|
||||||
|
// null 表示不限制
|
||||||
|
"SizeLimit": null,
|
||||||
|
|
||||||
|
// 内存压缩比例(0.0-1.0)
|
||||||
|
"CompactionPercentage": 0.25,
|
||||||
|
|
||||||
|
// 过期扫描频率(秒)
|
||||||
|
"ExpirationScanFrequency": 60
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 事件总线配置 (EventBus)
|
||||||
|
// 约定配置节名称:EventBus
|
||||||
|
// 用于:EventBus 模块 - AddEventBus()
|
||||||
|
// ========================================
|
||||||
|
"EventBus": {
|
||||||
|
// 是否启用异步处理
|
||||||
|
"EnableAsync": true,
|
||||||
|
|
||||||
|
// 异步事件队列容量
|
||||||
|
"QueueCapacity": 1000,
|
||||||
|
|
||||||
|
// 是否在异常时继续执行其他订阅者
|
||||||
|
"ContinueOnError": true,
|
||||||
|
|
||||||
|
// 是否启用死信队列
|
||||||
|
"EnableDeadLetterQueue": false,
|
||||||
|
|
||||||
|
// 死信队列容量
|
||||||
|
"DeadLetterQueueCapacity": 100
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// WPF配置 (Wpf)
|
||||||
|
// 约定配置节名称:Wpf
|
||||||
|
// 用于:Wpf 模块 - AddSharpWpf()
|
||||||
|
// ========================================
|
||||||
|
"Wpf": {
|
||||||
|
// 默认对话框标题
|
||||||
|
"DefaultDialogTitle": "提示",
|
||||||
|
|
||||||
|
// 是否启用全局异常处理
|
||||||
|
"EnableGlobalExceptionHandler": true,
|
||||||
|
|
||||||
|
// 主题
|
||||||
|
// 可选值:Light、Dark
|
||||||
|
"Theme": "Light",
|
||||||
|
|
||||||
|
// 语言
|
||||||
|
// 可选值:zh-CN、en-US
|
||||||
|
"Language": "zh-CN"
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 环境变量覆盖说明
|
||||||
|
// ========================================
|
||||||
|
// 所有配置都可以通过环境变量覆盖,格式:
|
||||||
|
// SHARP__{节名}__{键名}
|
||||||
|
//
|
||||||
|
// 示例:
|
||||||
|
// SHARP__Database__Provider=Sqlite
|
||||||
|
// SHARP__Database__ConnectionString=Data Source=test.db
|
||||||
|
// SHARP__Plc__Siemens__IpAddress=192.168.1.200
|
||||||
|
// SHARP__System__HttpPort=9090
|
||||||
|
//
|
||||||
|
// 注意:双下划线 __ 用于分隔层级
|
||||||
|
// ========================================
|
||||||
|
}
|
||||||
+5
-3
@@ -75,13 +75,11 @@ dotnet clean Sharp.sln
|
|||||||
|
|
||||||
```
|
```
|
||||||
src/Sharp/ # All source projects
|
src/Sharp/ # All source projects
|
||||||
├── Common/ # Core foundation (Result<T>, Global container, utilities)
|
├── Common/ # Core foundation (Result<T>, Global container, utilities, SystemConfig)
|
||||||
├── Config/ # Multi-format configuration with hot-reload
|
├── Config/ # Multi-format configuration with hot-reload
|
||||||
├── Sharp.Infrastructure/ # Infrastructure abstractions
|
|
||||||
├── Wpf/ # WPF UI toolkit (MVVM, dialogs, converters) - NO UI library dependency
|
├── Wpf/ # WPF UI toolkit (MVVM, dialogs, converters) - NO UI library dependency
|
||||||
├── Wpf.HandyControl/ # HandyControl UI library integration (optional)
|
├── Wpf.HandyControl/ # HandyControl UI library integration (optional)
|
||||||
├── Data/ # EF Core wrapper with repository pattern
|
├── Data/ # EF Core wrapper with repository pattern
|
||||||
├── Repository/ # Repository implementations
|
|
||||||
├── Log/ # Serilog-based structured logging
|
├── Log/ # Serilog-based structured logging
|
||||||
├── Cache/ # Memory cache (planned)
|
├── Cache/ # Memory cache (planned)
|
||||||
├── EventBus/ # Event pub/sub (planned)
|
├── EventBus/ # Event pub/sub (planned)
|
||||||
@@ -90,6 +88,8 @@ src/Sharp/ # All source projects
|
|||||||
├── Ports/ # Serial port abstraction (RS232/RS485)
|
├── Ports/ # Serial port abstraction (RS232/RS485)
|
||||||
├── Plc/ # PLC abstraction interface
|
├── Plc/ # PLC abstraction interface
|
||||||
├── Plc.Siemens/ # Siemens S7 PLC implementation (S7.NET+)
|
├── Plc.Siemens/ # Siemens S7 PLC implementation (S7.NET+)
|
||||||
|
├── Process/ # Process execution
|
||||||
|
├── Python/ # Python script execution
|
||||||
├── Client/ # WPF demo application
|
├── Client/ # WPF demo application
|
||||||
└── Server/ # WPF server example
|
└── Server/ # WPF server example
|
||||||
|
|
||||||
@@ -100,6 +100,8 @@ test/ # MSTest test projects
|
|||||||
├── Log.Test/
|
├── Log.Test/
|
||||||
├── NetClient.Test/
|
├── NetClient.Test/
|
||||||
└── NetServer.Test/
|
└── NetServer.Test/
|
||||||
|
|
||||||
|
../../appsettings.template.json # 完整的配置模板文件(约定配置节名称)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Key Architectural Patterns
|
### Key Architectural Patterns
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ using Client.ViewModels;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Common;
|
using Common;
|
||||||
|
using Common.Configuration;
|
||||||
using Config;
|
using Config;
|
||||||
using NetClient.DependencyInjection;
|
using NetClient.DependencyInjection;
|
||||||
using Sharp.Infrastructure.Configuration;
|
|
||||||
using Sharp.Log.Extensions;
|
using Sharp.Log.Extensions;
|
||||||
using Sharp.NetServer.DependencyInjection;
|
using Sharp.NetServer.DependencyInjection;
|
||||||
using Sharp.Wpf.Services;
|
using Sharp.Wpf.Services;
|
||||||
@@ -87,11 +87,10 @@ namespace Client
|
|||||||
// 2) Build DI container
|
// 2) Build DI container
|
||||||
var services = new ServiceCollection();
|
var services = new ServiceCollection();
|
||||||
|
|
||||||
// ConfigManager and typed SystemConfig accessor
|
// ConfigManager and IConfiguration
|
||||||
services.AddSingleton(cm);
|
services.AddSingleton(cm);
|
||||||
// Register standard IConfiguration so that .BindConfiguration() works
|
// Register standard IConfiguration so that .BindConfiguration() works
|
||||||
services.AddSingleton<IConfiguration>(cm.Configuration);
|
services.AddSingleton<IConfiguration>(cm.Configuration);
|
||||||
services.AddSystemConfig(cm);
|
|
||||||
|
|
||||||
// Logging (binds from section "SharpLog")
|
// Logging (binds from section "SharpLog")
|
||||||
services.AddLogging(b => b.AddSharpLog());
|
services.AddLogging(b => b.AddSharpLog());
|
||||||
@@ -136,7 +135,6 @@ namespace Client
|
|||||||
// 3) Register global facades for convenience
|
// 3) Register global facades for convenience
|
||||||
Global.RegisterSingleton<IServiceProvider>(_serviceProvider);
|
Global.RegisterSingleton<IServiceProvider>(_serviceProvider);
|
||||||
Global.RegisterSingleton(cm);
|
Global.RegisterSingleton(cm);
|
||||||
Global.RegisterSingleton(_serviceProvider.GetRequiredService<ISystemConfigAccessor>());
|
|
||||||
// Also register IDispatcher in Global if it's needed by static contexts (though injection is preferred)
|
// Also register IDispatcher in Global if it's needed by static contexts (though injection is preferred)
|
||||||
Global.RegisterSingleton(_serviceProvider.GetRequiredService<IDispatcher>());
|
Global.RegisterSingleton(_serviceProvider.GetRequiredService<IDispatcher>());
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
<ProjectReference Include="..\NetClient\NetClient.csproj" />
|
<ProjectReference Include="..\NetClient\NetClient.csproj" />
|
||||||
<ProjectReference Include="..\NetServer\NetServer.csproj" />
|
<ProjectReference Include="..\NetServer\NetServer.csproj" />
|
||||||
<ProjectReference Include="..\Log\Log.csproj" />
|
<ProjectReference Include="..\Log\Log.csproj" />
|
||||||
<ProjectReference Include="..\Sharp.Infrastructure\Sharp.Infrastructure.csproj" />
|
|
||||||
<ProjectReference Include="..\Plc.Siemens\Plc.Siemens.csproj" />
|
<ProjectReference Include="..\Plc.Siemens\Plc.Siemens.csproj" />
|
||||||
<ProjectReference Include="..\Ports\Ports.csproj" />
|
<ProjectReference Include="..\Ports\Ports.csproj" />
|
||||||
<ProjectReference Include="..\Process\Process.csproj" />
|
<ProjectReference Include="..\Process\Process.csproj" />
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
|
||||||
|
namespace Common.Configuration;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 系统级通用配置
|
||||||
|
/// 包含 HTTP 访问所需的基础字段,可被 NetClient/NetServer 等模块复用
|
||||||
|
/// 约定配置节名称:System
|
||||||
|
/// </summary>
|
||||||
|
public sealed class SystemConfig
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[RegularExpression(@"^([0-9]{1,3}\.){3}[0-9]{1,3}$|^localhost$|^[a-zA-Z0-9_.-]+$")]
|
||||||
|
public string HTTPIp { get; set; } = "127.0.0.1";
|
||||||
|
|
||||||
|
[Range(1, 65535)]
|
||||||
|
public int HttpPort { get; set; } = 8080;
|
||||||
|
|
||||||
|
[Range(1, 600)]
|
||||||
|
public int TimeoutSeconds { get; set; } = 30;
|
||||||
|
|
||||||
|
public string Scheme { get; set; } = "http";
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ using System;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Config;
|
using Config;
|
||||||
using NetClient.Options;
|
using NetClient.Options;
|
||||||
using Sharp.Infrastructure.Configuration;
|
using Common.Configuration;
|
||||||
|
|
||||||
namespace NetClient.DependencyInjection;
|
namespace NetClient.DependencyInjection;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Common\Common.csproj" />
|
<ProjectReference Include="..\Common\Common.csproj" />
|
||||||
<ProjectReference Include="..\Config\Config.csproj" />
|
<ProjectReference Include="..\Config\Config.csproj" />
|
||||||
<ProjectReference Include="..\Sharp.Infrastructure\Sharp.Infrastructure.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Config;
|
using Config;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Sharp.Infrastructure.Configuration;
|
using Common.Configuration;
|
||||||
using Sharp.NetServer.Server;
|
using Sharp.NetServer.Server;
|
||||||
|
|
||||||
namespace Sharp.NetServer.DependencyInjection;
|
namespace Sharp.NetServer.DependencyInjection;
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Common\Common.csproj" />
|
<ProjectReference Include="..\Common\Common.csproj" />
|
||||||
<ProjectReference Include="..\Config\Config.csproj" />
|
<ProjectReference Include="..\Config\Config.csproj" />
|
||||||
<ProjectReference Include="..\Sharp.Infrastructure\Sharp.Infrastructure.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
|
|
||||||
using Repository.Options;
|
|
||||||
|
|
||||||
namespace Repository;
|
|
||||||
|
|
||||||
internal static class DatabaseConfigurator
|
|
||||||
{
|
|
||||||
public static void Configure(DbContextOptionsBuilder builder, DatabaseConnectionOptions options)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(options.ConnectionString))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
$"Database connection '{options.ConnectionName ?? "Default"}' has an empty connection string.");
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.EnableDetailedErrors(options.EnableDetailedErrors);
|
|
||||||
builder.EnableSensitiveDataLogging(options.EnableSensitiveLogging);
|
|
||||||
|
|
||||||
switch (options.Provider)
|
|
||||||
{
|
|
||||||
case DatabaseProvider.SqlServer:
|
|
||||||
builder.UseSqlServer(options.ConnectionString, sql =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(options.MigrationsAssembly))
|
|
||||||
{
|
|
||||||
sql.MigrationsAssembly(options.MigrationsAssembly);
|
|
||||||
}
|
|
||||||
if (options.EnableRetryOnFailure)
|
|
||||||
{
|
|
||||||
sql.EnableRetryOnFailure(options.RetryCount, options.RetryDelay, errorNumbersToAdd: null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case DatabaseProvider.PostgreSql:
|
|
||||||
builder.UseNpgsql(options.ConnectionString, npgsql =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(options.MigrationsAssembly))
|
|
||||||
{
|
|
||||||
npgsql.MigrationsAssembly(options.MigrationsAssembly);
|
|
||||||
}
|
|
||||||
if (options.EnableRetryOnFailure)
|
|
||||||
{
|
|
||||||
npgsql.EnableRetryOnFailure(options.RetryCount, options.RetryDelay, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case DatabaseProvider.MySql:
|
|
||||||
var serverVersion = string.IsNullOrWhiteSpace(options.ServerVersion)
|
|
||||||
? ServerVersion.AutoDetect(options.ConnectionString)
|
|
||||||
: ServerVersion.Parse(options.ServerVersion);
|
|
||||||
builder.UseMySql(options.ConnectionString, serverVersion, mysql =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(options.MigrationsAssembly))
|
|
||||||
{
|
|
||||||
mysql.MigrationsAssembly(options.MigrationsAssembly);
|
|
||||||
}
|
|
||||||
if (options.EnableRetryOnFailure)
|
|
||||||
{
|
|
||||||
mysql.EnableRetryOnFailure(options.RetryCount, options.RetryDelay, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case DatabaseProvider.Sqlite:
|
|
||||||
builder.UseSqlite(options.ConnectionString, sqlite =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(options.MigrationsAssembly))
|
|
||||||
{
|
|
||||||
sqlite.MigrationsAssembly(options.MigrationsAssembly);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException($"Unsupported database provider '{options.Provider}'.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
using Config;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Repository.Initialization;
|
|
||||||
using Repository.Options;
|
|
||||||
|
|
||||||
namespace Repository.DependencyInjection;
|
|
||||||
|
|
||||||
public static class RepositoryServiceCollectionExtensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 依据配置中心 (ConfigManager) 注册 DbContext,自动选择数据库 Provider 并可选执行迁移。
|
|
||||||
/// </summary>
|
|
||||||
public static IServiceCollection AddSharpDbContext<TContext>(this IServiceCollection services,
|
|
||||||
ConfigManager configManager,
|
|
||||||
string section = "Database",
|
|
||||||
string? connectionName = null,
|
|
||||||
bool initializeOnStartup = true,
|
|
||||||
Action<DbContextOptionsBuilder>? configureBuilder = null,
|
|
||||||
ServiceLifetime contextLifetime = ServiceLifetime.Scoped,
|
|
||||||
ServiceLifetime optionsLifetime = ServiceLifetime.Scoped)
|
|
||||||
where TContext : DbContext
|
|
||||||
{
|
|
||||||
var databaseOptions = configManager.Get<DatabaseOptions>(section, validate: false) ?? new DatabaseOptions();
|
|
||||||
var connection = databaseOptions.Resolve(connectionName);
|
|
||||||
return services.AddSharpDbContext<TContext>(connection, initializeOnStartup, configureBuilder, contextLifetime, optionsLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 直接基于手动提供的 DatabaseConnectionOptions 注册 DbContext。
|
|
||||||
/// </summary>
|
|
||||||
public static IServiceCollection AddSharpDbContext<TContext>(this IServiceCollection services,
|
|
||||||
DatabaseConnectionOptions connection,
|
|
||||||
bool initializeOnStartup = true,
|
|
||||||
Action<DbContextOptionsBuilder>? configureBuilder = null,
|
|
||||||
ServiceLifetime contextLifetime = ServiceLifetime.Scoped,
|
|
||||||
ServiceLifetime optionsLifetime = ServiceLifetime.Scoped)
|
|
||||||
where TContext : DbContext
|
|
||||||
{
|
|
||||||
var resolved = connection.Clone();
|
|
||||||
services.AddDbContext<TContext>((sp, builder) =>
|
|
||||||
{
|
|
||||||
DatabaseConfigurator.Configure(builder, resolved);
|
|
||||||
configureBuilder?.Invoke(builder);
|
|
||||||
}, contextLifetime, optionsLifetime);
|
|
||||||
|
|
||||||
services.TryAddSingleton<IDatabaseInitializer<TContext>>(sp =>
|
|
||||||
new DatabaseInitializer<TContext>(sp, resolved, initializeOnStartup));
|
|
||||||
|
|
||||||
if (initializeOnStartup)
|
|
||||||
{
|
|
||||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService>(sp =>
|
|
||||||
(IHostedService)sp.GetRequiredService<IDatabaseInitializer<TContext>>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Repository.Options;
|
|
||||||
|
|
||||||
namespace Repository.Initialization;
|
|
||||||
|
|
||||||
internal sealed class DatabaseInitializer<TContext> : IDatabaseInitializer<TContext>, IHostedService
|
|
||||||
where TContext : DbContext
|
|
||||||
{
|
|
||||||
private readonly IServiceProvider _serviceProvider;
|
|
||||||
private readonly DatabaseConnectionOptions _options;
|
|
||||||
private readonly bool _runOnStartup;
|
|
||||||
|
|
||||||
public DatabaseInitializer(IServiceProvider serviceProvider, DatabaseConnectionOptions options, bool runOnStartup)
|
|
||||||
{
|
|
||||||
_serviceProvider = serviceProvider;
|
|
||||||
_options = options;
|
|
||||||
_runOnStartup = runOnStartup;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InitializeAsync(CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
using var scope = _serviceProvider.CreateScope();
|
|
||||||
var context = scope.ServiceProvider.GetRequiredService<TContext>();
|
|
||||||
|
|
||||||
if (_options.AutoMigrate)
|
|
||||||
{
|
|
||||||
await context.Database.MigrateAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await context.Database.EnsureCreatedAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (!_runOnStartup)
|
|
||||||
{
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
return InitializeAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace Repository.Initialization;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 提供数据库初始化(建库/迁移)能力。
|
|
||||||
/// </summary>
|
|
||||||
public interface IDatabaseInitializer<in TContext> where TContext : DbContext
|
|
||||||
{
|
|
||||||
Task InitializeAsync(CancellationToken cancellationToken = default);
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace Repository.Options;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 单个数据库连接的配置。
|
|
||||||
/// </summary>
|
|
||||||
public sealed class DatabaseConnectionOptions
|
|
||||||
{
|
|
||||||
[Required]
|
|
||||||
public string ConnectionString { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public DatabaseProvider Provider { get; set; } = DatabaseProvider.Sqlite;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 针对 MySQL/Pomelo 的服务器版本。留空则自动检测。
|
|
||||||
/// </summary>
|
|
||||||
public string? ServerVersion { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 指定迁移程序集;留空则使用 DbContext 所在程序集。
|
|
||||||
/// </summary>
|
|
||||||
public string? MigrationsAssembly { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否在启动时自动执行迁移(默认为 true)。
|
|
||||||
/// </summary>
|
|
||||||
public bool AutoMigrate { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启用失败重试。
|
|
||||||
/// </summary>
|
|
||||||
public bool EnableRetryOnFailure { get; set; } = true;
|
|
||||||
|
|
||||||
public int RetryCount { get; set; } = 5;
|
|
||||||
|
|
||||||
public TimeSpan RetryDelay { get; set; } = TimeSpan.FromSeconds(5);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 打印敏感日志(调试阶段可启用)。
|
|
||||||
/// </summary>
|
|
||||||
public bool EnableSensitiveLogging { get; set; }
|
|
||||||
|
|
||||||
public bool EnableDetailedErrors { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 供内部追踪当前连接名称。
|
|
||||||
/// </summary>
|
|
||||||
public string? ConnectionName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 克隆当前选项,避免多处引用同一实例。
|
|
||||||
/// </summary>
|
|
||||||
public DatabaseConnectionOptions Clone()
|
|
||||||
{
|
|
||||||
return new DatabaseConnectionOptions
|
|
||||||
{
|
|
||||||
ConnectionString = ConnectionString,
|
|
||||||
Provider = Provider,
|
|
||||||
ServerVersion = ServerVersion,
|
|
||||||
MigrationsAssembly = MigrationsAssembly,
|
|
||||||
AutoMigrate = AutoMigrate,
|
|
||||||
EnableRetryOnFailure = EnableRetryOnFailure,
|
|
||||||
RetryCount = RetryCount,
|
|
||||||
RetryDelay = RetryDelay,
|
|
||||||
EnableSensitiveLogging = EnableSensitiveLogging,
|
|
||||||
EnableDetailedErrors = EnableDetailedErrors,
|
|
||||||
ConnectionName = ConnectionName
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
namespace Repository.Options;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 数据库配置根节点,支持多命名连接。
|
|
||||||
/// </summary>
|
|
||||||
public sealed class DatabaseOptions
|
|
||||||
{
|
|
||||||
public string DefaultConnection { get; set; } = "Default";
|
|
||||||
|
|
||||||
public IDictionary<string, DatabaseConnectionOptions> Connections { get; set; } =
|
|
||||||
new Dictionary<string, DatabaseConnectionOptions>(StringComparer.OrdinalIgnoreCase)
|
|
||||||
{
|
|
||||||
["Default"] = new DatabaseConnectionOptions
|
|
||||||
{
|
|
||||||
Provider = DatabaseProvider.Sqlite,
|
|
||||||
ConnectionString = "Data Source=app.db"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public DatabaseConnectionOptions Resolve(string? connectionName = null)
|
|
||||||
{
|
|
||||||
var name = string.IsNullOrWhiteSpace(connectionName) ? DefaultConnection : connectionName;
|
|
||||||
if (!Connections.TryGetValue(name, out var options))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Connection '{name}' is not configured.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var clone = options.Clone();
|
|
||||||
clone.ConnectionName = name;
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace Repository.Options;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 支持的数据库提供器。
|
|
||||||
/// </summary>
|
|
||||||
public enum DatabaseProvider
|
|
||||||
{
|
|
||||||
SqlServer,
|
|
||||||
PostgreSql,
|
|
||||||
MySql,
|
|
||||||
Sqlite
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
# Sharp.Repository
|
|
||||||
|
|
||||||
面向 Sharp 套件的数据库集成模块,围绕 EF Core 封装“约定优于配置”的默认体验:通过一个配置段即可在 MySQL / SQL Server / PostgreSQL / Sqlite 之间切换,自动注册 `DbContext` 并在启动时执行 `Migration`/`EnsureCreated`。
|
|
||||||
|
|
||||||
## 功能
|
|
||||||
|
|
||||||
- **多 Provider**:内置 SQL Server、PostgreSQL、MySQL (Pomelo)、Sqlite,按配置自动选择 `UseXXX`.
|
|
||||||
- **多命名连接**:`Database.Connections` 支持任意命名,默认 `Default`.
|
|
||||||
- **自动迁移**:默认在应用启动(或手动调用)时执行 `context.Database.MigrateAsync()`。
|
|
||||||
- **DI 集成**:`services.AddSharpDbContext<TContext>(ConfigManager …)` 一行搞定配置绑定 + DbContext 注册 + 初始化器。
|
|
||||||
- **可扩展**:可选择禁用自动迁移、开启敏感日志/详细错误、指定迁移程序集、配置 MySQL ServerVersion。
|
|
||||||
|
|
||||||
## 配置示例
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"Database": {
|
|
||||||
"DefaultConnection": "Main",
|
|
||||||
"Connections": {
|
|
||||||
"Main": {
|
|
||||||
"Provider": "Sqlite",
|
|
||||||
"ConnectionString": "Data Source=app.db"
|
|
||||||
},
|
|
||||||
"Reporting": {
|
|
||||||
"Provider": "SqlServer",
|
|
||||||
"ConnectionString": "Server=.;Database=Sharp;Trusted_Connection=True;",
|
|
||||||
"EnableRetryOnFailure": true,
|
|
||||||
"MigrationsAssembly": "Server"
|
|
||||||
},
|
|
||||||
"Analytics": {
|
|
||||||
"Provider": "PostgreSql",
|
|
||||||
"ConnectionString": "Host=localhost;Database=analytics;Username=postgres;Password=123456"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 快速接入
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using Config;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Repository.DependencyInjection;
|
|
||||||
|
|
||||||
var cm = ConfigDefaults.BuildDefault();
|
|
||||||
|
|
||||||
services.AddSharpDbContext<AppDbContext>(cm, section: "Database", connectionName: "Main");
|
|
||||||
|
|
||||||
// 可选:如果没有 Host,可在启动时手动执行迁移
|
|
||||||
var initializer = serviceProvider.GetRequiredService<IDatabaseInitializer<AppDbContext>>();
|
|
||||||
await initializer.InitializeAsync();
|
|
||||||
```
|
|
||||||
|
|
||||||
默认会在 Host 启动时自动调用 `InitializeAsync`(借助 `IHostedService`)。若不想自动迁移,可在配置里设置 `AutoMigrate=false`,或者调用 `services.AddSharpDbContext(... initializeOnStartup: false)`。
|
|
||||||
|
|
||||||
## 手动選擇 Provider
|
|
||||||
|
|
||||||
若想在没有 Config 模块的场景手动注册:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
var connection = new DatabaseConnectionOptions
|
|
||||||
{
|
|
||||||
Provider = DatabaseProvider.MySql,
|
|
||||||
ConnectionString = "server=localhost;database=app;user=root;password=123456",
|
|
||||||
ServerVersion = "8.0.35",
|
|
||||||
AutoMigrate = true
|
|
||||||
};
|
|
||||||
|
|
||||||
services.AddSharpDbContext<AppDbContext>(connection);
|
|
||||||
```
|
|
||||||
|
|
||||||
## DbContext 模板
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class AppDbContext : DbContext
|
|
||||||
{
|
|
||||||
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
|
|
||||||
|
|
||||||
public DbSet<User> Users => Set<User>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class User
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
public string UserName { get; set; } = string.Empty;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
将 `Repository` 模块与 `Config` 结合后,使用者只需在 `appsettings.json` 填写连接串,即可获得可用的 `DbContext`,更复杂的配置(如连接池、命名策略)仍可沿用 EF Core 原本的扩展方法。
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.8" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.8" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
|
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
|
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Config\Config.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup />
|
|
||||||
</Project>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Sharp.Infrastructure
|
|
||||||
{
|
|
||||||
public class Class1
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using Config;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
||||||
|
|
||||||
namespace Sharp.Infrastructure.Configuration;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 官方示例:系统级通用配置。可由项目复制或修改,Config 模块本身不再内置业务模型。
|
|
||||||
/// 包含 HTTP 访问所需的基础字段,可被 NetClient/NetServer 等模块复用。
|
|
||||||
/// </summary>
|
|
||||||
public sealed class SystemConfig
|
|
||||||
{
|
|
||||||
[Required]
|
|
||||||
[RegularExpression(@"^([0-9]{1,3}\.){3}[0-9]{1,3}$|^localhost$|^[a-zA-Z0-9_.-]+$")]
|
|
||||||
public string HTTPIp { get; set; } = "127.0.0.1";
|
|
||||||
|
|
||||||
[Range(1, 65535)]
|
|
||||||
public int HttpPort { get; set; } = 8080;
|
|
||||||
|
|
||||||
[Range(1, 600)]
|
|
||||||
public int TimeoutSeconds { get; set; } = 30;
|
|
||||||
|
|
||||||
public string Scheme { get; set; } = "http";
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ISystemConfigAccessor
|
|
||||||
{
|
|
||||||
SystemConfig Value { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class SystemConfigAccessor : ISystemConfigAccessor, IDisposable
|
|
||||||
{
|
|
||||||
private readonly ConfigManager _configManager;
|
|
||||||
private readonly IDisposable _subscription;
|
|
||||||
private readonly string _section;
|
|
||||||
private readonly bool _validate;
|
|
||||||
private SystemConfig _current;
|
|
||||||
|
|
||||||
public SystemConfigAccessor(ConfigManager configManager, string section, bool validate)
|
|
||||||
{
|
|
||||||
_configManager = configManager;
|
|
||||||
_section = section;
|
|
||||||
_validate = validate;
|
|
||||||
_current = configManager.Get<SystemConfig>(_section, _validate);
|
|
||||||
_subscription = configManager.OnReload(() =>
|
|
||||||
{
|
|
||||||
_current = _configManager.Get<SystemConfig>(_section, _validate);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public SystemConfig Value => _current;
|
|
||||||
|
|
||||||
public void Dispose() => _subscription.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SystemConfigServiceCollectionExtensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Registers SystemConfig accessor backed by ConfigManager under the specified section (default "System").
|
|
||||||
/// </summary>
|
|
||||||
public static IServiceCollection AddSystemConfig(this IServiceCollection services, ConfigManager configManager, string section = "System", bool validate = false)
|
|
||||||
{
|
|
||||||
services.TryAddSingleton(configManager);
|
|
||||||
services.TryAddSingleton<ISystemConfigAccessor>(_ => new SystemConfigAccessor(configManager, section, validate));
|
|
||||||
services.TryAddSingleton(sp => sp.GetRequiredService<ISystemConfigAccessor>().Value);
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# Sharp.Infrastructure
|
|
||||||
|
|
||||||
基础设施层项目,通常用于存放解决方案级别的横切关注点或胶水代码,目前包含部分遗留配置或共享类型。
|
|
||||||
|
|
||||||
> **注意**:随着模块化重构的进行,本项目的许多职责已迁移至 `Common`、`Config` 等专门模块。当前主要作为兼容性保留或特定业务的基础设施依赖。
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Config\Config.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -19,12 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetClient", "NetClient\NetC
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetServer", "NetServer\NetServer.csproj", "{8223A4A8-DE17-4E26-A3EB-674E58B9C446}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetServer", "NetServer\NetServer.csproj", "{8223A4A8-DE17-4E26-A3EB-674E58B9C446}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Repository", "Repository\Repository.csproj", "{74D45E9E-A513-453F-B51D-5541D2857AB8}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Config.Test", "..\..\test\Config.Test\Config.Test.csproj", "{F48331AE-8662-411E-B789-A0158A4A1F21}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Config.Test", "..\..\test\Config.Test\Config.Test.csproj", "{F48331AE-8662-411E-B789-A0158A4A1F21}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sharp.Infrastructure", "Sharp.Infrastructure\Sharp.Infrastructure.csproj", "{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wpf", "Wpf\Wpf.csproj", "{FA8C6432-F42B-4A47-B0C1-60E1773E9CF7}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wpf", "Wpf\Wpf.csproj", "{FA8C6432-F42B-4A47-B0C1-60E1773E9CF7}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetClient.Test", "..\..\test\NetClient.Test\NetClient.Test.csproj", "{DE83D16E-72D4-4E54-B4D2-17D9CF4E09DD}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetClient.Test", "..\..\test\NetClient.Test\NetClient.Test.csproj", "{DE83D16E-72D4-4E54-B4D2-17D9CF4E09DD}"
|
||||||
@@ -159,18 +155,6 @@ Global
|
|||||||
{8223A4A8-DE17-4E26-A3EB-674E58B9C446}.Release|x64.Build.0 = Release|Any CPU
|
{8223A4A8-DE17-4E26-A3EB-674E58B9C446}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{8223A4A8-DE17-4E26-A3EB-674E58B9C446}.Release|x86.ActiveCfg = Release|Any CPU
|
{8223A4A8-DE17-4E26-A3EB-674E58B9C446}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{8223A4A8-DE17-4E26-A3EB-674E58B9C446}.Release|x86.Build.0 = Release|Any CPU
|
{8223A4A8-DE17-4E26-A3EB-674E58B9C446}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{74D45E9E-A513-453F-B51D-5541D2857AB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{74D45E9E-A513-453F-B51D-5541D2857AB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{74D45E9E-A513-453F-B51D-5541D2857AB8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{74D45E9E-A513-453F-B51D-5541D2857AB8}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{74D45E9E-A513-453F-B51D-5541D2857AB8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{74D45E9E-A513-453F-B51D-5541D2857AB8}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{74D45E9E-A513-453F-B51D-5541D2857AB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{74D45E9E-A513-453F-B51D-5541D2857AB8}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{74D45E9E-A513-453F-B51D-5541D2857AB8}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{74D45E9E-A513-453F-B51D-5541D2857AB8}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{74D45E9E-A513-453F-B51D-5541D2857AB8}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{74D45E9E-A513-453F-B51D-5541D2857AB8}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{F48331AE-8662-411E-B789-A0158A4A1F21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{F48331AE-8662-411E-B789-A0158A4A1F21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{F48331AE-8662-411E-B789-A0158A4A1F21}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{F48331AE-8662-411E-B789-A0158A4A1F21}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{F48331AE-8662-411E-B789-A0158A4A1F21}.Debug|x64.ActiveCfg = Debug|Any CPU
|
{F48331AE-8662-411E-B789-A0158A4A1F21}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
@@ -183,18 +167,6 @@ Global
|
|||||||
{F48331AE-8662-411E-B789-A0158A4A1F21}.Release|x64.Build.0 = Release|Any CPU
|
{F48331AE-8662-411E-B789-A0158A4A1F21}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{F48331AE-8662-411E-B789-A0158A4A1F21}.Release|x86.ActiveCfg = Release|Any CPU
|
{F48331AE-8662-411E-B789-A0158A4A1F21}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{F48331AE-8662-411E-B789-A0158A4A1F21}.Release|x86.Build.0 = Release|Any CPU
|
{F48331AE-8662-411E-B789-A0158A4A1F21}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{10DDCB28-9DF5-4BC7-8A3E-AA92275BBB40}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{FA8C6432-F42B-4A47-B0C1-60E1773E9CF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{FA8C6432-F42B-4A47-B0C1-60E1773E9CF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{FA8C6432-F42B-4A47-B0C1-60E1773E9CF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{FA8C6432-F42B-4A47-B0C1-60E1773E9CF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{FA8C6432-F42B-4A47-B0C1-60E1773E9CF7}.Debug|x64.ActiveCfg = Debug|Any CPU
|
{FA8C6432-F42B-4A47-B0C1-60E1773E9CF7}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
|||||||
Reference in new issue
Block a user