From 3b10c5f42868d6251a21b8d47ac784af6a9d5f29 Mon Sep 17 00:00:00 2001
From: d4ilys <963922242@qq.com>
Date: Thu, 16 Oct 2025 09:49:57 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96QuestDb=20IHttpClientFactory?=
=?UTF-8?q?=E5=8F=8AIServiceCollection=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../QuestDbGlobalExtensions.cs | 143 ++++++++++--------
.../QuestDbProvider.cs | 4 -
...uestDbContainer.cs => ServiceContainer.cs} | 12 +-
3 files changed, 89 insertions(+), 70 deletions(-)
rename Providers/FreeSql.Provider.QuestDb/{QuestDbContainer.cs => ServiceContainer.cs} (62%)
diff --git a/Providers/FreeSql.Provider.QuestDb/QuestDbGlobalExtensions.cs b/Providers/FreeSql.Provider.QuestDb/QuestDbGlobalExtensions.cs
index a047356a0..4d0a20efe 100644
--- a/Providers/FreeSql.Provider.QuestDb/QuestDbGlobalExtensions.cs
+++ b/Providers/FreeSql.Provider.QuestDb/QuestDbGlobalExtensions.cs
@@ -21,6 +21,7 @@ using System.Threading.Tasks;
using System.Web;
using FreeSql.Provider.QuestDb;
using System.Net;
+using Microsoft.Extensions.DependencyInjection;
public static partial class QuestDbGlobalExtensions
{
@@ -35,8 +36,51 @@ public static partial class QuestDbGlobalExtensions
private static readonly QuestDbAdo _questDbAdo = new QuestDbAdo();
- public static FreeSqlBuilder UseQuestDbRestAPI(this FreeSqlBuilder build, string host, string username = "",
- string password = "") => RestAPIExtension.UseQuestDbRestAPI(build, host, username, password);
+ ///
+ /// 启动QuestDb Http功能
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static FreeSqlBuilder UseQuestDbRestAPI(this FreeSqlBuilder builder, string host, string username = "",
+ string password = "")
+ {
+ //初始化容器,添加HttpClient
+ ServiceContainer.Initialize(service =>
+ {
+ service.AddHttpClient("QuestDb", client => client.BaseAddress = new Uri(host))
+ .ConfigurePrimaryHttpMessageHandler(handlerBuilder =>
+ {
+ //忽略SSL验证
+ return new HttpClientHandler
+ {
+ ClientCertificateOptions = ClientCertificateOption.Manual,
+ ServerCertificateCustomValidationCallback =
+ (httpRequestMessage, cert, certChain, policyErrors) => true
+ };
+ });
+
+ var description = new QuestResetApiFeatures()
+ {
+ BaseAddress = host
+ };
+
+ if (!string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
+ {
+ var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}"));
+ description.BasicToken = $"Basic {base64}";
+ }
+
+ service.AddSingleton(description);
+ });
+
+ //RestApi需要无参数
+ builder.UseNoneCommandParameter(true);
+
+ return builder;
+ }
///
/// 对于多个时间序列存储在同一个表中的场景,根据时间戳检索给定键或键组合的最新项。
@@ -50,7 +94,7 @@ public static partial class QuestDbGlobalExtensions
public static ISelect LatestOn(this ISelect select, Expression> timestamp,
Expression> partition)
{
- LatestOnExtension.InternelImpl(timestamp, partition);
+ LatestOnExtension.InternalImpl(timestamp, partition);
return select;
}
@@ -67,7 +111,7 @@ public static partial class QuestDbGlobalExtensions
Expression> timestamp,
Expression> partition) where T2 : class
{
- LatestOnExtension.InternelImpl(timestamp, partition);
+ LatestOnExtension.InternalImpl(timestamp, partition);
return select;
}
@@ -84,7 +128,7 @@ public static partial class QuestDbGlobalExtensions
Expression> timestamp,
Expression> partition) where T2 : class where T3 : class
{
- LatestOnExtension.InternelImpl(timestamp, partition);
+ LatestOnExtension.InternalImpl(timestamp, partition);
return select;
}
@@ -101,7 +145,7 @@ public static partial class QuestDbGlobalExtensions
Expression> timestamp,
Expression> partition) where T2 : class where T3 : class where T4 : class
{
- LatestOnExtension.InternelImpl(timestamp, partition);
+ LatestOnExtension.InternalImpl(timestamp, partition);
return select;
}
@@ -162,19 +206,19 @@ public static partial class QuestDbGlobalExtensions
public static async Task ExecuteQuestDbBulkCopyAsync(this IInsert that,
string dateFormat = "yyyy/M/d H:mm:ss") where T : class
{
- //思路:通过提供的RestAPI imp,实现快速复制
- if (string.IsNullOrWhiteSpace(RestAPIExtension.BaseUrl))
+ var features = ServiceContainer.GetService();
+
+ if (string.IsNullOrWhiteSpace(features.BaseAddress))
{
throw new Exception(
- "BulkCopy功能需要启用RestAPI,启用方式:new FreeSqlBuilder().UseQuestDbRestAPI(\"localhost:9000\", \"username\", \"password\")");
+ @"BulkCopy功能需要启用RestAPI,启用方式:new FreeSqlBuilder().UseQuestDbRestAPI(""localhost:9000"", ""username"", ""password"")");
}
var result = 0;
try
{
- var client = QuestDbContainer.GetService().CreateClient();
- var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
+ var boundary = $"---------------{DateTime.Now.Ticks:x}";
var list = new List();
var insert = that as QuestDbInsert;
var name = insert.InternalTableRuleInvoke(); //获取表名
@@ -199,7 +243,7 @@ public static partial class QuestDbGlobalExtensions
}
});
var schema = JsonConvert.SerializeObject(list);
- using (MemoryStream stream = new MemoryStream())
+ using (var stream = new MemoryStream())
{
//写入CSV文件
using (var writer = new StreamWriter(stream))
@@ -208,29 +252,27 @@ public static partial class QuestDbGlobalExtensions
await csv.WriteRecordsAsync(insert._source);
}
+ var client = features.HttpClient;
var httpContent = new MultipartFormDataContent(boundary);
- if (!string.IsNullOrWhiteSpace(RestAPIExtension.authorization))
- client.DefaultRequestHeaders.Add("Authorization", RestAPIExtension.authorization);
+ if (!string.IsNullOrWhiteSpace(features.BasicToken))
+ client.DefaultRequestHeaders.Add("Authorization", features.BasicToken);
httpContent.Add(new StringContent(schema), "schema");
httpContent.Add(new ByteArrayContent(stream.ToArray()), "data");
- //boundary带双引号 可能导致服务器错误情况
httpContent.Headers.Remove("Content-Type");
httpContent.Headers.TryAddWithoutValidation("Content-Type",
- "multipart/form-data; boundary=" + boundary);
+ $"multipart/form-data; boundary={boundary}");
var httpResponseMessage =
- await client.PostAsync($"{RestAPIExtension.BaseUrl}/imp?name={name}", httpContent);
+ await client.PostAsync($"imp?name={name}", httpContent);
var readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync();
var splitByLine = SplitByLine(readAsStringAsync);
- foreach (var s in splitByLine)
+ foreach (var strings in from s in splitByLine
+ where s.Contains("Rows")
+ select s.Split('|')
+ into strings
+ where strings[1].Trim() == "Rows imported"
+ select strings)
{
- if (s.Contains("Rows"))
- {
- var strings = s.Split('|');
- if (strings[1].Trim() == "Rows imported")
- {
- result = Convert.ToInt32(strings[2].Trim());
- }
- }
+ result = Convert.ToInt32(strings[2].Trim());
}
}
}
@@ -249,7 +291,8 @@ public static partial class QuestDbGlobalExtensions
///
/// 导入时,时间格式 默认:yyyy/M/d H:mm:ss
///
- public static int ExecuteQuestDbBulkCopy(this IInsert insert, string dateFormat = "yyyy/M/d H:mm:ss") where T : class
+ public static int ExecuteQuestDbBulkCopy(this IInsert insert, string dateFormat = "yyyy/M/d H:mm:ss")
+ where T : class
{
return ExecuteQuestDbBulkCopyAsync(insert, dateFormat).ConfigureAwait(false).GetAwaiter().GetResult();
}
@@ -294,7 +337,7 @@ static class LatestOnExtension
LatestOnString.Value = string.Empty;
}
- internal static void InternelImpl(Expression> timestamp,
+ internal static void InternalImpl(Expression> timestamp,
Expression> partition)
{
IsExistence.Value = true;
@@ -308,42 +351,22 @@ static class LatestOnExtension
}
}
-static class RestAPIExtension
+class QuestResetApiFeatures
{
- internal static string BaseUrl = string.Empty;
- internal static string authorization = string.Empty;
+ internal string BaseAddress { get; set; }
- internal static async Task ExecAsync(string sql)
+ internal string BasicToken { get; set; }
+
+ internal HttpClient HttpClient => ServiceContainer.GetService().CreateClient("QuestDb");
+
+ internal async Task ExecAsync(string sql)
{
//HTTP GET 执行SQL
- var result = string.Empty;
- var client = QuestDbContainer.GetService().CreateClient();
- var url = $"{BaseUrl}/exec?query={HttpUtility.UrlEncode(sql)}";
- if (!string.IsNullOrWhiteSpace(authorization))
- client.DefaultRequestHeaders.Add("Authorization", authorization);
- var httpResponseMessage = await client.GetAsync(url);
- result = await httpResponseMessage.Content.ReadAsStringAsync();
+ var url = $"exec?query={HttpUtility.UrlEncode(sql)}";
+ if (!string.IsNullOrWhiteSpace(BasicToken))
+ HttpClient.DefaultRequestHeaders.Add("Authorization", BasicToken);
+ var httpResponseMessage = await HttpClient.GetAsync(url);
+ var result = await httpResponseMessage.Content.ReadAsStringAsync();
return result;
}
-
- internal static FreeSqlBuilder UseQuestDbRestAPI(FreeSqlBuilder buider, string host, string username = "",
- string password = "")
- {
- BaseUrl = host;
- if (BaseUrl.EndsWith("/"))
- BaseUrl = BaseUrl.Remove(BaseUrl.Length - 1);
-
- if (!BaseUrl.ToLower().StartsWith("http"))
- BaseUrl = $"http://{BaseUrl}";
- //生成TOKEN
- if (!string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
- {
- var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}"));
- authorization = $"Basic {base64}";
- }
-
- //RestApi需要无参数
- buider.UseNoneCommandParameter(true);
- return buider;
- }
}
\ No newline at end of file
diff --git a/Providers/FreeSql.Provider.QuestDb/QuestDbProvider.cs b/Providers/FreeSql.Provider.QuestDb/QuestDbProvider.cs
index f937b8290..31c038006 100644
--- a/Providers/FreeSql.Provider.QuestDb/QuestDbProvider.cs
+++ b/Providers/FreeSql.Provider.QuestDb/QuestDbProvider.cs
@@ -118,10 +118,6 @@ namespace FreeSql.QuestDb
Select0Provider._dicMethodDataReaderGetValue[typeof(Guid)] =
typeof(DbDataReader).GetMethod("GetGuid", new Type[] { typeof(int) });
- QuestDbContainer.Initialize(service =>
- {
- service.AddHttpClient();
- });
}
}
diff --git a/Providers/FreeSql.Provider.QuestDb/QuestDbContainer.cs b/Providers/FreeSql.Provider.QuestDb/ServiceContainer.cs
similarity index 62%
rename from Providers/FreeSql.Provider.QuestDb/QuestDbContainer.cs
rename to Providers/FreeSql.Provider.QuestDb/ServiceContainer.cs
index fb678d721..31049dcf3 100644
--- a/Providers/FreeSql.Provider.QuestDb/QuestDbContainer.cs
+++ b/Providers/FreeSql.Provider.QuestDb/ServiceContainer.cs
@@ -1,21 +1,21 @@
using System;
using System.Collections.Generic;
+using System.Net.Http;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
namespace FreeSql.Provider.QuestDb
{
- internal class QuestDbContainer
+ internal class ServiceContainer
{
- //作用于HttpClientFatory
- private static IServiceCollection Services;
+ private static IServiceCollection _services;
internal static IServiceProvider ServiceProvider { get; private set; }
internal static void Initialize(Action service)
{
- Services = new ServiceCollection();
- service?.Invoke(Services);
- ServiceProvider = Services.BuildServiceProvider();
+ _services = new ServiceCollection();
+ service?.Invoke(_services);
+ ServiceProvider = _services.BuildServiceProvider();
}
internal static T GetService()