Merge pull request '🥕 迁移远程请求配置到业务层;修复部分已知bug' (#434) from jasondom/Admin.NET.Pro:v2-1 into v2

Reviewed-on: https://code.adminnet.top/Admin.NET/Admin.NET.Pro/pulls/434
This commit is contained in:
zuohuaijun 2025-08-30 15:14:11 +08:00
commit 96f1709af7
14 changed files with 87 additions and 89 deletions

View File

@ -0,0 +1,20 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Furion.ConfigurableOptions;
namespace Admin.NET.Application;
/// <summary>
/// 远程请求配置
/// </summary>
public sealed class HttpRemotesOptions : IConfigurableOptions
{
/// <summary>
/// 企业微信
/// </summary>
public HttpRemoteItem WorkWeixin { get; set; }
}

View File

@ -6,7 +6,7 @@
namespace Admin.NET.Application; namespace Admin.NET.Application;
public class RabbitMqHandler : IMessageHandler public class RabbitMqHandler : IMessageHandler, ISingleton
{ {
public string QueueName => "admin.net.rabbitmq"; // 队列名称 public string QueueName => "admin.net.rabbitmq"; // 队列名称

View File

@ -19,13 +19,16 @@ public class Startup : AppStartup
var consumerCount = option.ConsumerCount.ToIntOrDefault(1); var consumerCount = option.ConsumerCount.ToIntOrDefault(1);
// 注册RabbitMQ服务 // 注册RabbitMQ服务
services.AddRabbitMQ<RabbitMqHandler>(consumerCount); services.AddRabbitMQ(consumerCount);
// 后台服务异常,不影响主程序(配置的服务器连接异常) // 后台服务异常,不影响主程序(配置的服务器连接异常)
services.Configure<HostOptions>(options => services.Configure<HostOptions>(options =>
{ {
options.BackgroundServiceExceptionBehavior = BackgroundServiceExceptionBehavior.Ignore; options.BackgroundServiceExceptionBehavior = BackgroundServiceExceptionBehavior.Ignore;
}); });
// 添加远程请求服务配置
services.AddConfigurableOptions<HttpRemotesOptions>();
} }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

View File

@ -4,6 +4,8 @@
// //
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using HandlebarsDotNet;
namespace Admin.NET.Core; namespace Admin.NET.Core;
/// <summary> /// <summary>
@ -23,10 +25,9 @@ public static class HttpRemotesExtension
/// <returns></returns> /// <returns></returns>
public static IServiceCollection AddHttpRemoteClientService(this IServiceCollection services) public static IServiceCollection AddHttpRemoteClientService(this IServiceCollection services)
{ {
var options = App.GetOptions<HttpRemotesOptions>() ?? throw new Exception("未正确配置HttpRemotes.json"); var options = App.Configuration.GetSection("HttpRemotes").GetChildren().Select(u => u.Get<HttpRemoteItem>());
foreach (var prop in options.GetType().GetProperties()) foreach (var opt in options)
{ {
if (prop.GetValue(options) is not HttpRemoteItem opt) continue;
services.AddHttpClient(opt.HttpName, client => services.AddHttpClient(opt.HttpName, client =>
{ {
client.BaseAddress = new Uri(opt.BaseAddress); client.BaseAddress = new Uri(opt.BaseAddress);
@ -112,4 +113,45 @@ public static class HttpRemotesExtension
} }
return null; return null;
} }
}
/// <summary>
/// 远程请求配置项
/// </summary>
public sealed class HttpRemoteItem
{
/// <summary>
/// 是否启用日志
/// </summary>
public bool EnabledLog { get; set; }
/// <summary>
/// 是否启用代理
/// </summary>
public bool EnabledProxy { get; set; }
/// <summary>
/// 服务名称
/// </summary>
public string HttpName { get; set; }
/// <summary>
/// 服务地址
/// </summary>
public string BaseAddress { get; set; }
/// <summary>
/// 请求超时时间
/// </summary>
public int Timeout { get; set; }
/// <summary>
/// 是否自动处理Cookie
/// </summary>
public bool UseCookies { get; set; }
/// <summary>
/// 请求头
/// </summary>
public Dictionary<string, string> Headers { get; set; }
} }

View File

@ -28,6 +28,8 @@ public class SysDailyJob(IServiceScopeFactory serviceScopeFactory) : IJob
await db.Deleteable<SysLogOp>().Where(u => u.CreateTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); await db.Deleteable<SysLogOp>().Where(u => u.CreateTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken);
// 删除差异日志 // 删除差异日志
await db.Deleteable<SysLogDiff>().Where(u => u.CreateTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); await db.Deleteable<SysLogDiff>().Where(u => u.CreateTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken);
// 删除请求日志
await db.Deleteable<SysLogHttp>().Where(u => u.CreateTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken);
// 删除作业触发器运行记录 // 删除作业触发器运行记录
await db.Deleteable<SysJobTriggerRecord>().Where(u => u.CreatedTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); await db.Deleteable<SysJobTriggerRecord>().Where(u => u.CreatedTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken);

View File

@ -12,9 +12,7 @@ namespace Admin.NET.Core;
public class HttpLoggingHandler : DelegatingHandler, ITransient public class HttpLoggingHandler : DelegatingHandler, ITransient
{ {
private static readonly Lazy<UserManager> UserManager = new(() => App.GetService<UserManager>()); private static readonly Lazy<UserManager> UserManager = new(() => App.GetService<UserManager>());
private static readonly string HttpNameKey = "__HTTP_CLIENT_NAME__"; private readonly Dictionary<string, HttpRemoteItem> _optionMap;
private readonly Dictionary<string, bool> _enabledLogMap;
private readonly SysConfigService _sysConfigService; private readonly SysConfigService _sysConfigService;
private readonly IEventPublisher _eventPublisher; private readonly IEventPublisher _eventPublisher;
@ -22,12 +20,9 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
{ {
_eventPublisher = eventPublisher; _eventPublisher = eventPublisher;
_sysConfigService = sysConfigService; _sysConfigService = sysConfigService;
_optionMap = App.Configuration.GetSection("HttpRemotes").GetChildren()
var options = App.GetOptions<HttpRemotesOptions>() ?? throw new Exception("[HttpRemote] 未正确配置HttpRemotes.json"); .Select(u => u.Get<HttpRemoteItem>())
_enabledLogMap = options.GetType().GetProperties() .ToDictionary(opt => opt.HttpName, opt => opt);
.Where(u => u.PropertyType == typeof(HttpRemoteItem))
.ToDictionary(u => u.GetValue(options) is HttpRemoteItem opt ? opt.HttpName : throw new Exception("[HttpRemote] 未正确配置HttpName"),
u => u.GetValue(options) is HttpRemoteItem { EnabledLog: true });
} }
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
@ -40,7 +35,7 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
// 判断当前配置日志开关 // 判断当前配置日志开关
var httpClientName = request.GetHttpClientName(); var httpClientName = request.GetHttpClientName();
var attr = request.GetHttpRemoteApiAttr(); var attr = request.GetHttpRemoteApiAttr();
if (!string.IsNullOrWhiteSpace(httpClientName)) enabledLog = _enabledLogMap.GetOrDefault(httpClientName); if (!string.IsNullOrWhiteSpace(httpClientName)) enabledLog = _optionMap.GetOrDefault(httpClientName).EnabledLog;
if (!enabledLog || attr?.IgnoreLog == true) return await base.SendAsync(request, cancellationToken); if (!enabledLog || attr?.IgnoreLog == true) return await base.SendAsync(request, cancellationToken);
var stopWatch = Stopwatch.StartNew(); var stopWatch = Stopwatch.StartNew();
@ -84,7 +79,7 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
finally finally
{ {
sysLogHttp.Elapsed = stopWatch.ElapsedMilliseconds; sysLogHttp.Elapsed = stopWatch.ElapsedMilliseconds;
await _eventPublisher.PublishAsync(nameof(AppEventSubscriber.CreateHttpLog), sysLogHttp); await _eventPublisher.PublishAsync(nameof(AppEventSubscriber.CreateHttpLog), sysLogHttp, cancellationToken);
} }
} }
} }

View File

@ -1,59 +0,0 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary>
/// 远程请求配置
/// </summary>
public sealed class HttpRemotesOptions : IConfigurableOptions
{
/// <summary>
/// 企业微信
/// </summary>
public HttpRemoteItem WorkWeixin { get; set; }
}
/// <summary>
/// 远程请求配置项
/// </summary>
public sealed class HttpRemoteItem
{
/// <summary>
/// 是否启用日志
/// </summary>
public bool EnabledLog { get; set; }
/// <summary>
/// 是否启用代理
/// </summary>
public bool EnabledProxy { get; set; }
/// <summary>
/// 服务名称
/// </summary>
public string HttpName { get; set; }
/// <summary>
/// 服务地址
/// </summary>
public string BaseAddress { get; set; }
/// <summary>
/// 请求超时时间
/// </summary>
public int Timeout { get; set; }
/// <summary>
/// 是否自动处理Cookie
/// </summary>
public bool UseCookies { get; set; }
/// <summary>
/// 请求头
/// </summary>
public Dictionary<string, string> Headers { get; set; }
}

View File

@ -14,15 +14,10 @@ public static class RabbitMQSetup
/// <param name="services"></param> /// <param name="services"></param>
/// <param name="consumerCount">消费者数量默认1个</param> /// <param name="consumerCount">消费者数量默认1个</param>
/// <returns></returns> /// <returns></returns>
public static void AddRabbitMQ<THandler>(this IServiceCollection services, int consumerCount = 1) public static void AddRabbitMQ(this IServiceCollection services, int consumerCount = 1)
where THandler : class, IMessageHandler
{ {
if (App.GetConfig<string>("EventBus:EventSourceType", true) != "RabbitMQ") return; if (App.GetConfig<string>("EventBus:EventSourceType", true) != "RabbitMQ") return;
services.AddSingleton<IMessageHandler, THandler>();
services.AddSingleton<RabbitMqConnection>();
services.AddSingleton<RabbitMqProducer>();
// 注册多个消费者服务 // 注册多个消费者服务
for (int i = 0; i < consumerCount; i++) for (int i = 0; i < consumerCount; i++)
{ {

View File

@ -8,7 +8,7 @@ using RabbitMQ.Client;
namespace Admin.NET.Core; namespace Admin.NET.Core;
public class RabbitMqConnection public class RabbitMqConnection : ISingleton
{ {
private IConnection _connection; private IConnection _connection;
private IChannel _channel; private IChannel _channel;

View File

@ -11,7 +11,7 @@ namespace Admin.NET.Core;
/// <summary> /// <summary>
/// 生产者 /// 生产者
/// </summary> /// </summary>
public class RabbitMqProducer public class RabbitMqProducer : ISingleton
{ {
private readonly RabbitMqConnection _connection; private readonly RabbitMqConnection _connection;

View File

@ -380,12 +380,13 @@ public static class SqlSugarSetup
// 初始化文本简称表数据 // 初始化文本简称表数据
if (config.ConfigId.ToString() == SqlSugarConst.MainConfigId) dbProvider.InitTextAbbData(); if (config.ConfigId.ToString() == SqlSugarConst.MainConfigId) dbProvider.InitTextAbbData();
// 由于修改定时任务后数据库无法更新,先清空定时任务数据 #region ,,
if (config.ConfigId.ToString() == SqlSugarConst.MainConfigId) if (config.ConfigId.ToString() == SqlSugarConst.MainConfigId)
{ {
dbProvider.DbMaintenance.TruncateTable<SysJobDetail>(); dbProvider.Deleteable<SysJobDetail>().Where(u => u.JobId == "job_log").ExecuteCommandAsync();
dbProvider.DbMaintenance.TruncateTable<SysJobTrigger>(); dbProvider.Deleteable<SysJobTrigger>().Where(u => u.TriggerId == "trigger_log").ExecuteCommandAsync();
} }
#endregion ,,
} }
/// <summary> /// <summary>

View File

@ -39,7 +39,6 @@ public static class ProjectOptions
services.AddConfigurableOptions<RabbitMqConsumerOptions>(); services.AddConfigurableOptions<RabbitMqConsumerOptions>();
services.AddConfigurableOptions<AlipayOptions>(); services.AddConfigurableOptions<AlipayOptions>();
services.AddConfigurableOptions<MqttOptions>(); services.AddConfigurableOptions<MqttOptions>();
services.AddConfigurableOptions<HttpRemotesOptions>();
services.Configure<IpRateLimitOptions>(App.Configuration.GetSection("IpRateLimiting")); services.Configure<IpRateLimitOptions>(App.Configuration.GetSection("IpRateLimiting"));
services.Configure<IpRateLimitPolicies>(App.Configuration.GetSection("IpRateLimitPolicies")); services.Configure<IpRateLimitPolicies>(App.Configuration.GetSection("IpRateLimitPolicies"));
services.Configure<ClientRateLimitOptions>(App.Configuration.GetSection("ClientRateLimiting")); services.Configure<ClientRateLimitOptions>(App.Configuration.GetSection("ClientRateLimiting"));

View File

@ -59,7 +59,7 @@ public class BaseIdWorkWxOutput : BaseWorkWxOutput
/// 获取接口凭证输入参数 /// 获取接口凭证输入参数
/// </summary> /// </summary>
/// https://developer.work.weixin.qq.com/document/path/91039 /// https://developer.work.weixin.qq.com/document/path/91039
[HttpRemoteApi(Action = "gettoken", Desc = "获取接口凭证", HttpMethod = HttpMethodEnum.Get, IgnoreLog = false)] [HttpRemoteApi(Action = "gettoken", Desc = "获取接口凭证", HttpMethod = HttpMethodEnum.Get, IgnoreLog = true)]
public class TokenWorkWxInput public class TokenWorkWxInput
{ {
/// <summary> /// <summary>

View File

@ -20,7 +20,7 @@ public class WorkWxBaseService(
SysConfigService sysConfigService, SysConfigService sysConfigService,
IHttpRemoteService httpRemoteService) : ITransient IHttpRemoteService httpRemoteService) : ITransient
{ {
private static readonly Lazy<HttpRemoteItem> Options = new(() => App.GetOptions<HttpRemotesOptions>().WorkWeixin); private static readonly Lazy<HttpRemoteItem> Options = new(() => App.GetConfig<HttpRemoteItem>("HttpRemotes:WorkWeixin", true));
/// <summary> /// <summary>
/// 获取企业微信接口凭证 /// 获取企业微信接口凭证