- Model层新增AdminConfig实体和AdminConfigReadDbContext(只读连接Admin库) - API项目新增AdminConnection连接字符串,注册AdminConfigReadDbContext - Core层ConfigService按key路由:运营配置走Admin库,业务配置走业务库 - WechatPayConfigService改为从Admin库读取支付/小程序配置 - WechatService新增AdminConfigReadDbContext注入,配置读取改为Admin库 - Autofac注册同步更新三个服务的依赖注入 - Admin.Business的AdminConfigService改用AdminConfigDbContext连接Admin库
206 lines
6.4 KiB
C#
206 lines
6.4 KiB
C#
using System.Text.Json;
|
||
using MiAssessment.Core.Interfaces;
|
||
using MiAssessment.Model.Data;
|
||
using MiAssessment.Model.Models.Config;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.Logging;
|
||
|
||
namespace MiAssessment.Core.Services;
|
||
|
||
/// <summary>
|
||
/// 配置服务实现
|
||
/// 运营配置(app_setting、base等)从 Admin 库读取
|
||
/// 业务配置从业务库读取
|
||
/// </summary>
|
||
public class ConfigService : IConfigService
|
||
{
|
||
private readonly MiAssessmentDbContext _dbContext;
|
||
private readonly AdminConfigReadDbContext _adminConfigDbContext;
|
||
private readonly ILogger<ConfigService> _logger;
|
||
private readonly IRedisService _redisService;
|
||
|
||
// 当前版本号
|
||
private const string CurrentVersion = "116";
|
||
|
||
/// <summary>
|
||
/// 需要从 Admin 库读取的运营配置键
|
||
/// </summary>
|
||
private static readonly HashSet<string> AdminConfigKeys = new()
|
||
{
|
||
"app_setting", "base", "weixinpay_setting", "miniprogram_setting",
|
||
"weixinpay", "alipay_setting", "h5_setting", "uploads",
|
||
"systemconfig", "sign", "user_config", "infinite_multiple",
|
||
"rank_setting", "system_test", "tencent_sms_config"
|
||
};
|
||
|
||
public ConfigService(
|
||
MiAssessmentDbContext dbContext,
|
||
AdminConfigReadDbContext adminConfigDbContext,
|
||
ILogger<ConfigService> logger,
|
||
IRedisService redisService)
|
||
{
|
||
_dbContext = dbContext;
|
||
_adminConfigDbContext = adminConfigDbContext;
|
||
_logger = logger;
|
||
_redisService = redisService;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<ConfigResponseDto> GetConfigAsync()
|
||
{
|
||
var response = new ConfigResponseDto
|
||
{
|
||
Version = CurrentVersion
|
||
};
|
||
|
||
// 获取应用设置
|
||
var appSettingJson = await GetConfigValueAsync("app_setting");
|
||
if (!string.IsNullOrEmpty(appSettingJson))
|
||
{
|
||
try
|
||
{
|
||
response.AppSetting = JsonSerializer.Deserialize<AppSettingDto>(appSettingJson,
|
||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogWarning(ex, "Failed to deserialize app_setting config");
|
||
}
|
||
}
|
||
|
||
// 获取基础配置
|
||
var baseConfigJson = await GetConfigValueAsync("base");
|
||
if (!string.IsNullOrEmpty(baseConfigJson))
|
||
{
|
||
try
|
||
{
|
||
var baseConfig = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(baseConfigJson,
|
||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||
|
||
if (baseConfig != null)
|
||
{
|
||
response.BaseConfig = new BaseConfigDto
|
||
{
|
||
IsShouTan = GetIntValue(baseConfig, "is_shou_tan"),
|
||
JumpAppid = GetStringValue(baseConfig, "jump_appid"),
|
||
Corpid = GetStringValue(baseConfig, "corpid"),
|
||
WxLink = GetStringValue(baseConfig, "wx_link")
|
||
};
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogWarning(ex, "Failed to deserialize base config");
|
||
}
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Task<PlatformConfigDto> GetPlatformConfigAsync(string? platform)
|
||
{
|
||
// 根据平台返回不同配置
|
||
// isWebPay = false 表示直接拉起微信支付,true 表示走客服消息支付
|
||
var config = new PlatformConfigDto
|
||
{
|
||
IsWebPay = false // 默认关闭 Web 支付,使用原生微信支付
|
||
};
|
||
|
||
// 可以根据 platform 参数返回不同配置
|
||
// 例如: MP-WEIXIN, WEB_H5, APP_ANDROID 等
|
||
// 目前所有平台都使用原生支付
|
||
|
||
return Task.FromResult(config);
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<string?> GetConfigValueAsync(string key)
|
||
{
|
||
// 尝试从缓存获取
|
||
var cacheKey = $"config:{key}";
|
||
try
|
||
{
|
||
var cachedValue = await _redisService.GetStringAsync(cacheKey);
|
||
if (!string.IsNullOrEmpty(cachedValue))
|
||
{
|
||
return cachedValue;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogWarning(ex, "Failed to get config from cache: {Key}", key);
|
||
}
|
||
|
||
// 根据配置键决定从哪个库读取
|
||
string? config;
|
||
if (AdminConfigKeys.Contains(key))
|
||
{
|
||
// 运营配置从 Admin 库读取
|
||
config = await _adminConfigDbContext.AdminConfigs
|
||
.Where(c => c.ConfigKey == key)
|
||
.Select(c => c.ConfigValue)
|
||
.FirstOrDefaultAsync();
|
||
}
|
||
else
|
||
{
|
||
// 业务配置从业务库读取
|
||
config = await _dbContext.Configs
|
||
.Where(c => c.ConfigKey == key)
|
||
.Select(c => c.ConfigValue)
|
||
.FirstOrDefaultAsync();
|
||
}
|
||
|
||
// 存入缓存(10分钟过期)
|
||
if (!string.IsNullOrEmpty(config))
|
||
{
|
||
try
|
||
{
|
||
await _redisService.SetStringAsync(cacheKey, config, TimeSpan.FromMinutes(10));
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogWarning(ex, "Failed to cache config: {Key}", key);
|
||
}
|
||
}
|
||
|
||
return config;
|
||
}
|
||
|
||
#region Private Helper Methods
|
||
|
||
private static int GetIntValue(Dictionary<string, JsonElement> dict, string key)
|
||
{
|
||
if (dict.TryGetValue(key, out var element))
|
||
{
|
||
if (element.ValueKind == JsonValueKind.Number)
|
||
{
|
||
return element.GetInt32();
|
||
}
|
||
if (element.ValueKind == JsonValueKind.String && int.TryParse(element.GetString(), out var value))
|
||
{
|
||
return value;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
private static string? GetStringValue(Dictionary<string, JsonElement> dict, string key)
|
||
{
|
||
if (dict.TryGetValue(key, out var element))
|
||
{
|
||
if (element.ValueKind == JsonValueKind.String)
|
||
{
|
||
return element.GetString();
|
||
}
|
||
if (element.ValueKind != JsonValueKind.Null)
|
||
{
|
||
return element.ToString();
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
#endregion
|
||
}
|