修复因数据库连接未及时释放而导致的频繁程序崩溃问题
优化部分代码实现细节
This commit is contained in:
parent
308787072d
commit
db1b7bbb7d
12 changed files with 82 additions and 86 deletions
|
|
@ -107,6 +107,9 @@ namespace iFileProxy.Config
|
|||
[JsonPropertyName("MaxConnectionPoolSize")]
|
||||
public uint MaxConnectionPoolSize { get; set; } = 50;
|
||||
|
||||
[JsonPropertyName("ConnectionLifeTime")]
|
||||
public uint ConnectionLifeTime { get; set; } = 120;
|
||||
|
||||
[JsonPropertyName("Common")]
|
||||
public Common Common { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -18,15 +18,6 @@ namespace iFileProxy.Controllers
|
|||
public DatabaseGateService _dbGateService = dbGateService;
|
||||
private readonly Serilog.ILogger _logger = Log.Logger.ForContext<ManagementController>();
|
||||
|
||||
|
||||
// 查看任务详情
|
||||
// 删除任务
|
||||
// 停止任务
|
||||
// 查看任务Process信息
|
||||
// 立即执行任务
|
||||
// 查看系统配置
|
||||
// 获取全部任务信息
|
||||
|
||||
/// <summary>
|
||||
/// 获取任务列表(支持分页)
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@ using Microsoft.AspNetCore.Mvc;
|
|||
using Serilog;
|
||||
using System.Web;
|
||||
using System.Net;
|
||||
using iFileProxy.Helpers; // 用于 URL 解码
|
||||
using iFileProxy.Helpers;
|
||||
using iFileProxy.Services; // 用于 URL 解码
|
||||
|
||||
namespace iFileProxy.Controllers
|
||||
{
|
||||
[Route("/")]
|
||||
public class StreamProxyController(IHttpClientFactory httpClientFactory, AppConfig appConfig) : ControllerBase
|
||||
public class StreamProxyController(IHttpClientFactory httpClientFactory, AppConfig appConfig, DatabaseGateService dbGateService) : ControllerBase
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
|
||||
private long SizeLimit = appConfig.StreamProxyOptions.SizeLimit;
|
||||
|
|
@ -151,12 +152,25 @@ namespace iFileProxy.Controllers
|
|||
|
||||
// 设置响应头:告诉浏览器这是一个文件下载
|
||||
var fileName = HttpUtility.UrlEncode(Path.GetFileName(new Uri(targetUrl).LocalPath)); // 对文件名进行编码 防止报错
|
||||
Response.Headers.Add("Content-Disposition", $"attachment; filename={fileName}");
|
||||
Response.Headers.Append("Content-Disposition", $"attachment; filename={fileName}");
|
||||
Response.ContentType = response.Content.Headers.ContentType?.ToString() ?? "application/octet-stream";
|
||||
|
||||
if (contentLength > 0)
|
||||
Response.ContentLength = contentLength;
|
||||
|
||||
await dbGateService.AddTaskInfoDataAsync(new TaskInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Size = contentLength ?? -1L,
|
||||
ClientIp = MasterHelper.GetClientIPAddr(HttpContext),
|
||||
AddTime = DateTime.UtcNow,
|
||||
UpdateTime = DateTime.UtcNow,
|
||||
Status = TaskState.Stream,
|
||||
TaskId = Guid.NewGuid().ToString(),
|
||||
Url = proxyUrl,
|
||||
Tag = "STREAM"
|
||||
});
|
||||
|
||||
// 流式转发文件
|
||||
using (var stream = await response.Content.ReadAsStreamAsync())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ namespace iFileProxy.Controllers
|
|||
|
||||
[HttpPost]
|
||||
[Route("/AddOfflineTask")]
|
||||
public ActionResult<CommonRsp> AddOfflineTask()
|
||||
public async Task<ActionResult<CommonRsp>> AddOfflineTask()
|
||||
{
|
||||
return _taskManager.AddTask(HttpContext) switch
|
||||
return await _taskManager.AddTask(HttpContext) switch
|
||||
{
|
||||
TaskAddState.Success => (ActionResult<CommonRsp>)Ok(new CommonRsp() { Retcode = (int)TaskAddState.Success, Message = "succ" }),
|
||||
TaskAddState.Fail => (ActionResult<CommonRsp>)Ok(new CommonRsp() { Retcode = (int)TaskAddState.Fail, Message = "unkown error!" }),
|
||||
|
|
@ -122,8 +122,8 @@ namespace iFileProxy.Controllers
|
|||
var fileInfo = new FileInfo(filePath);
|
||||
|
||||
// 设置响应头
|
||||
Response.Headers.Add("Content-Disposition", $"attachment; filename=\"{fileName}\"");
|
||||
Response.Headers.Add("Content-Length", fileInfo.Length.ToString());
|
||||
Response.Headers.Append("Content-Disposition", $"attachment; filename=\"{fileName}\"");
|
||||
Response.Headers.Append("Content-Length", fileInfo.Length.ToString());
|
||||
|
||||
// 使用 FileStream 进行流式传输
|
||||
var fileStream = new FileStream(
|
||||
|
|
|
|||
|
|
@ -16,7 +16,10 @@
|
|||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
if (appConfig.SecurityOptions.BlockedClientIP.IndexOf(MasterHelper.GetClientIPAddr(context)) != -1)
|
||||
string ipStr = MasterHelper.GetClientIPAddr(context);
|
||||
|
||||
// 处理配置文件拉黑IP
|
||||
if (appConfig.SecurityOptions.BlockedClientIP.IndexOf(ipStr) != -1)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
await context.Response.WriteAsJsonAsync(new CommonRsp { Retcode = 403, Message = "你的IP地址已经被管理员拉入黑名单!"});
|
||||
|
|
@ -26,16 +29,6 @@
|
|||
// 获取需要跟踪的路由列表
|
||||
var routesToTrack = appConfig.SecurityOptions.RoutesToTrack;
|
||||
|
||||
// 检查当前请求的路径是否在需要跟踪的路由列表中
|
||||
foreach (var p in routesToTrack)
|
||||
{
|
||||
if (context.Request.Path.ToString().StartsWith(p, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 如果匹配到需要跟踪的路由,继续处理请求
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有匹配到需要跟踪的路由,直接调用下一个中间件
|
||||
if (!routesToTrack.Any(p => context.Request.Path.ToString().StartsWith(p, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
|
|
@ -44,29 +37,27 @@
|
|||
}
|
||||
|
||||
string dateStr = DateTime.Now.ToString("yyyy-MM-dd");
|
||||
string ipStr = MasterHelper.GetClientIPAddr(context);
|
||||
|
||||
if (_IPAccessCountDict.ContainsKey(dateStr))
|
||||
|
||||
if (!_IPAccessCountDict.TryGetValue(dateStr, out var ipCounts))
|
||||
{
|
||||
if (_IPAccessCountDict[dateStr].ContainsKey(ipStr))
|
||||
ipCounts = [];
|
||||
_IPAccessCountDict[dateStr] = ipCounts;
|
||||
}
|
||||
|
||||
if (ipCounts.TryGetValue(ipStr, out uint value))
|
||||
{
|
||||
if (ipCounts[ipStr] >= appConfig.SecurityOptions.DailyRequestLimitPerIP)
|
||||
{
|
||||
if (_IPAccessCountDict[dateStr][ipStr] >= appConfig.SecurityOptions.DailyRequestLimitPerIP)
|
||||
{
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.ContentType = "application/json";
|
||||
await context.Response.WriteAsync(JsonSerializer.Serialize(new CommonRsp { Retcode = 403, Message = "日请求次数超过限制! (GMT+8 时间00:00重置)" }));
|
||||
return;
|
||||
}
|
||||
_IPAccessCountDict[dateStr][ipStr]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
_IPAccessCountDict[dateStr].Add(ipStr, 1);
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.ContentType = "application/json";
|
||||
await context.Response.WriteAsync(JsonSerializer.Serialize(new CommonRsp { Retcode = 403, Message = "日请求次数超过限制! (GMT+8 时间00:00重置)" }));
|
||||
return;
|
||||
}
|
||||
ipCounts[ipStr] = ++value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_IPAccessCountDict.Add(dateStr, new Dictionary<string, uint> { { ipStr, 1 } });
|
||||
ipCounts.Add(ipStr, 1);
|
||||
}
|
||||
|
||||
await _next(context);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using iFileProxy.Helpers;
|
||||
using iFileProxy.Models;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
|
|
@ -6,16 +7,10 @@ using System.Text;
|
|||
|
||||
namespace iFileProxy.Middleware
|
||||
{
|
||||
public class JwtMiddleware
|
||||
public class JwtMiddleware(RequestDelegate next, IConfiguration configuration)
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
public JwtMiddleware(RequestDelegate next, IConfiguration configuration)
|
||||
{
|
||||
_next = next;
|
||||
_configuration = configuration;
|
||||
}
|
||||
private readonly RequestDelegate _next = next;
|
||||
private readonly IConfiguration _configuration = configuration;
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
|
|
@ -30,7 +25,7 @@ namespace iFileProxy.Middleware
|
|||
{
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var key = Encoding.ASCII.GetBytes(_configuration["Jwt:Key"]);
|
||||
|
||||
|
||||
// 验证token
|
||||
tokenHandler.ValidateToken(token, new TokenValidationParameters
|
||||
{
|
||||
|
|
@ -44,18 +39,19 @@ namespace iFileProxy.Middleware
|
|||
}, out SecurityToken validatedToken);
|
||||
|
||||
var jwtToken = (JwtSecurityToken)validatedToken;
|
||||
|
||||
|
||||
// 验证客户端信息
|
||||
var tokenFingerprint = jwtToken.Claims.First(x => x.Type == "fingerprint").Value;
|
||||
var tokenUserAgent = jwtToken.Claims.First(x => x.Type == "userAgent").Value;
|
||||
var tokenIp = jwtToken.Claims.First(x => x.Type == "ip").Value;
|
||||
|
||||
// 如果客户端信息不匹配,则拒绝访问
|
||||
if (fingerprint != tokenFingerprint ||
|
||||
userAgent != tokenUserAgent ||
|
||||
if (fingerprint != tokenFingerprint ||
|
||||
userAgent != tokenUserAgent ||
|
||||
(ip != tokenIp && !IsLocalNetwork(ip, tokenIp))) // 允许本地网络IP变化
|
||||
{
|
||||
context.Response.StatusCode = 401;
|
||||
await context.Response.WriteAsJsonAsync(new CommonRsp { Message = "环境发生变化, 请重新验证", Retcode = 401});
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -71,14 +67,14 @@ namespace iFileProxy.Middleware
|
|||
await _next(context);
|
||||
}
|
||||
|
||||
private bool IsLocalNetwork(string? ip1, string? ip2)
|
||||
private static bool IsLocalNetwork(string? ip1, string? ip2)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ip1) || string.IsNullOrEmpty(ip2)) return false;
|
||||
|
||||
|
||||
// 检查是否都是内网IP
|
||||
return (ip1.StartsWith("192.168.") && ip2.StartsWith("192.168.")) ||
|
||||
(ip1.StartsWith("10.") && ip2.StartsWith("10.")) ||
|
||||
(ip1.StartsWith("172.") && ip2.StartsWith("172."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,10 @@
|
|||
/// </summary>
|
||||
Canceled = 7,
|
||||
/// <summary>
|
||||
/// 流任务
|
||||
/// </summary>
|
||||
Stream = 8,
|
||||
/// <summary>
|
||||
/// 其他
|
||||
/// </summary>
|
||||
Other = 999
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|||
using Microsoft.IdentityModel.Tokens;
|
||||
using Serilog;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace iFileProxy
|
||||
{
|
||||
|
|
|
|||
|
|
@ -148,8 +148,8 @@ namespace iFileProxy.Services
|
|||
Password = db_password,
|
||||
Pooling = true,
|
||||
MinimumPoolSize = 1,
|
||||
MaximumPoolSize = AppConfig.GetCurrConfig().Database.MaxConnectionPoolSize,
|
||||
ConnectionLifeTime = 300 // 连接最大生命周期(秒)
|
||||
MaximumPoolSize = _appConfig.Database.MaxConnectionPoolSize,
|
||||
ConnectionLifeTime = _appConfig.Database.ConnectionLifeTime // 连接最大生命周期(秒)
|
||||
};
|
||||
|
||||
try
|
||||
|
|
@ -170,10 +170,9 @@ namespace iFileProxy.Services
|
|||
foreach (var db in _dbDictionary)
|
||||
{
|
||||
_logger.Information($"[程序启动前配置验证] 正在测试数据库配置: {db.Key} ...");
|
||||
MySqlConnection dbConn = new();
|
||||
try
|
||||
{
|
||||
dbConn = GetAndOpenDBConn(db.Key);
|
||||
using MySqlConnection dbConn = GetAndOpenDBConn(db.Key);
|
||||
_logger.Information($"succ.");
|
||||
}
|
||||
catch (Exception)
|
||||
|
|
@ -181,10 +180,6 @@ namespace iFileProxy.Services
|
|||
_logger.Fatal($"=========== 数据库: {db.Key} 测试失败! ===========");
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
dbConn.Close();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -250,7 +245,7 @@ namespace iFileProxy.Services
|
|||
public List<TaskInfo> CheckCacheDependencies(string taskId,string ipAddr)
|
||||
{
|
||||
string sql = $"SELECT * FROM t_tasks_info WHERE `status` = @status AND `tag` = @tag AND `client_ip` <> @ip_addr";
|
||||
MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
using MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
try
|
||||
{
|
||||
using MySqlCommand sqlCmd = new(sql, conn);
|
||||
|
|
@ -271,7 +266,7 @@ namespace iFileProxy.Services
|
|||
public string GetTaskListByStateAndIp(string ipAddr, TaskState status)
|
||||
{
|
||||
string sql = $"SELECT * FROM t_tasks_info WHERE client_ip = @ip_addr AND `status` = @status";
|
||||
MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
using MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
try
|
||||
{
|
||||
using MySqlCommand sqlCmd = new(sql, conn);
|
||||
|
|
@ -291,7 +286,7 @@ namespace iFileProxy.Services
|
|||
public string GetTaskListByIP(string ipAddr)
|
||||
{
|
||||
string sql = $"SELECT * FROM t_tasks_info WHERE client_ip = @ip_addr";
|
||||
MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
using MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
try
|
||||
{
|
||||
using MySqlCommand sqlCmd = new (sql,conn);
|
||||
|
|
@ -308,7 +303,7 @@ namespace iFileProxy.Services
|
|||
public string GetTaskInfoByTid(string tid)
|
||||
{
|
||||
string sql = $"SELECT * FROM t_tasks_info WHERE `tid` = @tid";
|
||||
MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
using MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
try
|
||||
{
|
||||
using MySqlCommand sqlCmd = new(sql, conn);
|
||||
|
|
@ -326,7 +321,7 @@ namespace iFileProxy.Services
|
|||
public TaskInfo? QueryTaskInfo(string fileName, string url, long size, TaskState status)
|
||||
{
|
||||
string sql = $"SELECT * FROM t_tasks_info WHERE url = @url AND size = @size AND `status` = @status AND file_name = @fileName";
|
||||
MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
using MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
try {
|
||||
MySqlCommand sqlCmd = new MySqlCommand(sql, conn);
|
||||
sqlCmd.Parameters.AddWithValue("@url", url);
|
||||
|
|
@ -351,12 +346,12 @@ namespace iFileProxy.Services
|
|||
|
||||
}
|
||||
|
||||
public bool InsertTaskData(TaskInfo taskInfo)
|
||||
public async Task<bool> AddTaskInfoDataAsync(TaskInfo taskInfo)
|
||||
{
|
||||
_logger.Debug(System.Text.Json.JsonSerializer.Serialize(taskInfo));
|
||||
string sql = "INSERT INTO `t_tasks_info` (`tid`, `file_name`, `client_ip`, `add_time`, `update_time`, `status`, `url`, `size`, `hash`, `tag`) " +
|
||||
"VALUES (@tid, @file_name, @client_ip, @add_time, @update_time, @status, @url, @size, @hash, @tag)";
|
||||
MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
using MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -372,7 +367,7 @@ namespace iFileProxy.Services
|
|||
sqlCmd.Parameters.AddWithValue("@hash", taskInfo.Hash);
|
||||
sqlCmd.Parameters.AddWithValue("@tag", taskInfo.Tag);
|
||||
|
||||
sqlCmd.ExecuteNonQuery();
|
||||
await sqlCmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
|
@ -388,7 +383,7 @@ namespace iFileProxy.Services
|
|||
public bool UpdateFieldsData(string fieldsName, string taskUUID,object val)
|
||||
{
|
||||
string sql = $"UPDATE t_tasks_info set `{fieldsName}` = @Data WHERE `tid` = @tid";
|
||||
MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
using MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
try
|
||||
{
|
||||
using MySqlCommand sqlCmd = new(sql, conn);
|
||||
|
|
@ -531,7 +526,7 @@ namespace iFileProxy.Services
|
|||
public PagedResult<TaskInfo> GetPagedTaskList(int page, int pageSize, TaskState? status = null)
|
||||
{
|
||||
// 构建基础SQL
|
||||
var sql = new StringBuilder("SELECT * FROM t_tasks_info");
|
||||
var sql = new StringBuilder($"SELECT * FROM t_tasks_info WHERE `status` <> {(int)TaskState.Stream}");
|
||||
var parameters = new Dictionary<string, object>();
|
||||
|
||||
// 添加状态过滤
|
||||
|
|
@ -547,7 +542,7 @@ namespace iFileProxy.Services
|
|||
parameters.Add("@limit", pageSize);
|
||||
|
||||
// 获取总记录数
|
||||
var countSql = "SELECT COUNT(*) FROM t_tasks_info" +
|
||||
var countSql = $"SELECT COUNT(*) FROM t_tasks_info WHERE `status` <> {(int)TaskState.Stream}" +
|
||||
(status.HasValue ? " AND status = @status" : "");
|
||||
var totalCount = ExecuteScalar<long>(countSql, parameters);
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ namespace iFileProxy.Services
|
|||
// 获取数据库中超出生命周期的缓存数据
|
||||
string sql = $@"SELECT * FROM t_tasks_info
|
||||
WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(update_time) > {CACHE_LIFETIME}
|
||||
AND (tag <> 'CLEANED' OR tag IS NULL)";
|
||||
AND (tag <> 'CLEANED' AND tag <> 'STREAM' AND `status` <> {(int)TaskState.Stream} OR tag IS NULL )";
|
||||
|
||||
List<TaskInfo>? taskInfos;
|
||||
using (var conn = _dbGateService.GetAndOpenDBConn(DbConfigName.iFileProxy))
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ namespace iFileProxy.Services
|
|||
/// </summary>
|
||||
/// <param name="c">HttpContext</param>
|
||||
/// <returns></returns>
|
||||
public TaskAddState AddTask(HttpContext c)
|
||||
public async Task<TaskAddState> AddTask(HttpContext c)
|
||||
{
|
||||
string? clientIp = MasterHelper.GetClientIPAddr(c);
|
||||
string? t_url = c.Request.Query["url"].FirstOrDefault() ?? c.Request.Form["url"].FirstOrDefault();
|
||||
|
|
@ -152,7 +152,7 @@ namespace iFileProxy.Services
|
|||
return TaskAddState.ErrQueueLengthLimit;
|
||||
|
||||
_pendingTasks.Enqueue(taskInfo); // 加入等待队列
|
||||
var status = AddTaskInfoToDb(taskInfo,true);
|
||||
var status = await AddTaskInfoToDb(taskInfo,true);
|
||||
_logger.Information($"[TaskId: {taskInfo.TaskId}] Queuing...");
|
||||
if (status != TaskAddState.Success) { return status; }
|
||||
return TaskAddState.Pending;
|
||||
|
|
@ -170,7 +170,7 @@ namespace iFileProxy.Services
|
|||
}
|
||||
}
|
||||
|
||||
return AddTaskInfoToDb(taskInfo);
|
||||
return await AddTaskInfoToDb(taskInfo);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -181,9 +181,9 @@ namespace iFileProxy.Services
|
|||
/// <param name="taskInfo">任务信息</param>
|
||||
/// <param name="queuing">是否正在排队 若正在排队则不开始任务 等待任务调度</param>
|
||||
/// <returns></returns>
|
||||
public TaskAddState AddTaskInfoToDb(TaskInfo taskInfo, bool queuing = false)
|
||||
public async Task<TaskAddState> AddTaskInfoToDb(TaskInfo taskInfo, bool queuing = false)
|
||||
{
|
||||
if (_dbGateService.InsertTaskData(taskInfo))
|
||||
if (await _dbGateService.AddTaskInfoDataAsync(taskInfo))
|
||||
{
|
||||
if (!queuing) // 如果不是正在排队的任务
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"Database": {
|
||||
"MaxConnectionPoolSize": 100,
|
||||
"MaxConnectionPoolSize": 100,
|
||||
"ConnectionLifeTime": 120,
|
||||
"Common": {
|
||||
"Host": "47.243.56.137",
|
||||
"Port": 3306,
|
||||
|
|
|
|||
Loading…
Reference in a new issue