Skip to content

Commit 2d4affa

Browse files
authored
Merge pull request #313 from Senparc/Develop-ApiClient
Develop api client
2 parents a12bec0 + 5193295 commit 2d4affa

File tree

15 files changed

+611
-283
lines changed

15 files changed

+611
-283
lines changed

src/Senparc.CO2NET.Tests/WebApi/ApiBind/ApiBindAttributeTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public void GetNameTest()
2424
{
2525
var method = typeof(TestClass).GetMethod("Func");
2626
var attr = new ApiBindAttribute();
27-
var result = attr.GetName(method);
27+
var result = attr.GetApiBindAttrName(method);
2828
Assert.AreEqual("TestClass.Func", result);
2929
}
3030
}

src/Senparc.CO2NET.WebApi/Senparc.CO2NET.WebApi.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFrameworks>netstandard2.1;net8.0</TargetFrameworks>
4-
<Version>2.0.0-beta2</Version>
4+
<Version>2.0.0-beta3</Version>
55
<LangVersion>latest</LangVersion>
66
<AssemblyName>Senparc.CO2NET.WebApi</AssemblyName>
77
<RootNamespace>Senparc.CO2NET.WebApi</RootNamespace>
88
<GeneratePackageOnBuild Condition=" '$(Configuration)' == 'Release' ">true</GeneratePackageOnBuild>
99
<Description>
1010
Senparc.CO2NET.WebApi Application Performance Management
1111
</Description>
12-
<Copyright>Senparc Copyright © 2004~2023</Copyright>
12+
<Copyright>Senparc Copyright © 2004~2024</Copyright>
1313
<PackageTags>WebApi,.NET Core,.NET Framework,Public,Base Library,CO2NET,盛派</PackageTags>
1414
<Authors>Senparc</Authors>
1515
<Owners>Senparc</Owners>

src/Senparc.CO2NET.WebApi/WebApiEngines/WebApiEngine.cs

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
Modification Description: v2.0.0-beta2 1. Add UseLowerCaseApiName to WebApiEngineOptions
1515
2. Add unique WebApi name to duplicate method name
1616
17+
Modification Identifier:Senparc - 20241119
18+
Modification Description:v3.0.0-beta3 reconstruction
1719
----------------------------------------------------------------*/
1820

1921
using Microsoft.AspNetCore.Mvc;
@@ -105,11 +107,6 @@ internal void WriteLog(string msg, bool hideLog = false)
105107
#region Create dynamic assembly related
106108

107109

108-
/// <summary>
109-
/// Match keywords to be replaced from apiBindInfo.Value.GlobalName
110-
/// </summary>
111-
private static Regex regexForMethodName = new Regex(@"[\.\-/:]", RegexOptions.Compiled);
112-
113110

114111
/// <summary>
115112
/// Create dynamic WebApi
@@ -229,10 +226,10 @@ await BuildApiMethodForOneThread(apiBindGroup, apiBindInfoBlock, apiMethodName,
229226
/// Generate API methods (Method) for a single thread (or Task), smallest granularity
230227
/// </summary>
231228
private async Task BuildApiMethodForOneThread(IGrouping<string, KeyValuePair<string, ApiBindInfo>> apiBindGroup,
232-
KeyValuePair<string, ApiBindInfo>[] apiBindInfoBlock, ConcurrentDictionary<string, string> apiMethodName, string keyName,
229+
KeyValuePair<string, ApiBindInfo>[] apiBindInfoBlock, ConcurrentDictionary<string, string> apiMethodName, string controllerKeyName,
233230
TypeBuilder tb, FieldBuilder fbServiceProvider, int apiIndex)
234231
{
235-
foreach (var apiBindInfo in apiBindInfoBlock)
232+
foreach (var apiBindInfoKv in apiBindInfoBlock)
236233
{
237234
#region ApiBuild
238235

@@ -244,28 +241,30 @@ private async Task BuildApiMethodForOneThread(IGrouping<string, KeyValuePair<str
244241
//}
245242

246243
var category = apiBindGroup.Key;
244+
var apiBindInfo = apiBindInfoKv.Value;
247245

248246
//Define version number
249247
if (!ApiAssemblyVersions.ContainsKey(category))
250248
{
251-
ApiAssemblyVersions[category] = apiBindInfo.Value.MethodInfo.DeclaringType.Assembly.GetName().Version.ToString(3);
249+
ApiAssemblyVersions[category] = apiBindInfo.MethodInfo.DeclaringType.Assembly.GetName().Version.ToString(3);
252250
}
253251

254252
//Current method name
255-
var methodName = regexForMethodName.Replace(apiBindInfo.Value.GlobalName, "_");
256-
var apiBindGlobalName = apiBindInfo.Value.GlobalName.Split('.')[0];
257-
var apiBindName = apiBindInfo.Value.Name.Split('.')[0];
258-
var indexOfApiGroupDot = apiBindInfo.Value.GlobalName.IndexOf(".");
259-
var apiName = apiBindInfo.Value.GlobalName.Substring(indexOfApiGroupDot + 1, apiBindInfo.Value.GlobalName.Length - indexOfApiGroupDot - 1);
253+
var globalName = apiBindInfo.GlobalName;
254+
255+
var methodName = apiBindInfo.MethodName;
256+
//var apiBindGlobalName = globalName.Split('.')[0];
257+
var apiBindName = apiBindInfo.ApiBindName;
258+
var apiName = apiBindInfo.ApiName;
260259

261260
//Current API's MethodInfo
262-
MethodInfo apiMethodInfo = apiBindInfo.Value.MethodInfo;
261+
MethodInfo apiMethodInfo = apiBindInfo.MethodInfo;
263262
//All parameter information of the current API
264263
var parameters = apiMethodInfo.GetParameters();
265264

266-
var apiLog = $"> Search DynamicApi[{apiIndex}]: {keyName} > ";
265+
var apiLog = $"> Search DynamicApi[{apiIndex}]: {controllerKeyName} > ";
267266
var prefixIndex = apiLog.Length;//For alignment indentation
268-
apiLog += $"{apiBindInfo.Key}";
267+
apiLog += $"{category}";
269268

270269
WriteLog(apiLog, true);
271270
WriteLog($"-> {methodName} - Parameters: {parameters.Count()}".PadLeft(prefixIndex), true);
@@ -277,7 +276,7 @@ private async Task BuildApiMethodForOneThread(IGrouping<string, KeyValuePair<str
277276
{
278277
//开发过程中可能会因为接口增加,导致重复名称的后缀改变,因此使用相对差异更大的方式增加后缀(将所有参数名、类型的字符串长度相加)
279278
//TODO:这种做法仍然无法解决第一个名称的命名问题(需要转回去修改)
280-
methodName += "_"+ getMethodUniqueNo;
279+
methodName += "_" + getMethodUniqueNo;
281280
apiName += "_" + getMethodUniqueNo;
282281
}
283282
apiMethodName[methodName] = apiName;
@@ -293,7 +292,7 @@ private async Task BuildApiMethodForOneThread(IGrouping<string, KeyValuePair<str
293292

294293
//Controller has already used SwaggerOperationAttribute once
295294
var t2_3 = typeof(SwaggerOperationAttribute);
296-
var tagName = new[] { $"{keyName}:{apiBindName}" };
295+
var tagName = new[] { $"{controllerKeyName}:{apiBindName}" };
297296
var tagAttrBuilder = new CustomAttributeBuilder(t2_3.GetConstructor(new Type[] { typeof(string), typeof(string) }),
298297
new object[] { (string)null, (string)null },
299298
new[] { t2_3.GetProperty("Tags") }, new[] { tagName });
@@ -305,9 +304,7 @@ private async Task BuildApiMethodForOneThread(IGrouping<string, KeyValuePair<str
305304
//[Route("/api/...", Name="xxx")]
306305
var t2_4 = typeof(RouteAttribute);
307306
//var routeName = apiBindInfo.Value.ApiBindAttribute.Name.Split('.')[0];
308-
var apiBindGroupNamePath = apiBindName.Replace(":", "_");
309-
var apiNamePath = apiName.Replace(":", "_");
310-
var apiPath = $"/api/{keyName}/{apiBindGroupNamePath}/{apiNamePath}{showStaticApiState}";
307+
string apiPath = GetApiPath(apiBindInfo, showStaticApiState);
311308

312309
//强制所有名称小写
313310
if (_useLowerCaseApiName)
@@ -324,7 +321,7 @@ private async Task BuildApiMethodForOneThread(IGrouping<string, KeyValuePair<str
324321
WriteLog($"Added DynamicApi Path: {apiPath}{System.Environment.NewLine}", true);
325322

326323
//[HttpPost]
327-
var specialMethod = apiBindInfo.Value.ApiBindAttribute.ApiRequestMethod;
324+
var specialMethod = apiBindInfo.ApiBindAttribute.ApiRequestMethod;
328325
if (specialMethod == ApiRequestMethod.GlobalDefault)
329326
{
330327
specialMethod = _defaultRequestMethod;//Use global default
@@ -477,6 +474,19 @@ private async Task BuildApiMethodForOneThread(IGrouping<string, KeyValuePair<str
477474
}
478475
}
479476

477+
public static string GetApiPath(ApiBindInfo apiBindInfo, string showStaticApiState)
478+
{
479+
return GetApiPath(apiBindInfo.ControllerKeyName, apiBindInfo.ApiBindName, apiBindInfo.ApiName, showStaticApiState);
480+
}
481+
482+
public static string GetApiPath(string keyName, string apiBindName, string apiName, string showStaticApiState)
483+
{
484+
var apiBindGroupNamePath = apiBindName.Replace(":", "_");
485+
var apiNamePath = apiName.Replace(":", "_");
486+
var apiPath = $"/api/{keyName}/{apiBindGroupNamePath}/{apiNamePath}{showStaticApiState}";
487+
return apiPath;
488+
}
489+
480490
/// <summary>
481491
/// Create internal call of API method
482492
/// </summary>
@@ -602,7 +612,7 @@ private BuildDynamicAssemblyResult BuildDynamicAssembly(string assembleName, IGr
602612

603613
//Store API
604614
//_apiCollection[category] = new Dictionary<string, ApiBindInfo>(apiBindGroup);
605-
var controllerKeyName = category.Replace(":", "_");//Do not change the rules arbitrarily, global consistency is required
615+
var controllerKeyName = ApiBindInfo.GetControllerKeyName(category);//Do not change the rules arbitrarily, global consistency is required
606616

607617
WriteLog($"search key: {category} -> {controllerKeyName}", true);
608618

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#region Apache License Version 2.0
2+
/*----------------------------------------------------------------
3+
4+
Copyright 2024 Suzhou Senparc Network Technology Co.,Ltd.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
7+
except in compliance with the License. You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software distributed under the
12+
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13+
either express or implied. See the License for the specific language governing permissions
14+
and limitations under the License.
15+
16+
Detail: https://github.com/Senparc/Senparc.CO2NET/blob/master/LICENSE
17+
18+
----------------------------------------------------------------*/
19+
#endregion Apache License Version 2.0
20+
21+
/*----------------------------------------------------------------
22+
Copyright (C) 2024 Senparc
23+
24+
文件名:ApiClient.cs
25+
文件功能描述:ApiClient, used to provide APiClient Container, work for such as Aspire.
26+
27+
28+
创建标识:Senparc - 20241118
29+
30+
----------------------------------------------------------------*/
31+
32+
33+
#if !NET462
34+
using Microsoft.Extensions.DependencyInjection;
35+
using Senparc.CO2NET.Extensions;
36+
using Senparc.CO2NET.HttpUtility;
37+
using System;
38+
using System.Collections.Generic;
39+
using System.Text;
40+
41+
namespace Senparc.CO2NET
42+
{
43+
/// <summary>
44+
/// ApiClient, used to provide APiClient Container, work for such as Aspire.
45+
/// </summary>
46+
public sealed class ApiClient
47+
{
48+
public SenparcHttpClient SenparcHttpClient { get; private set; }
49+
50+
internal ApiClient(IServiceProvider serviceProvider,string httpClientName, string apiClientName)
51+
{
52+
SenparcHttpClient = SenparcHttpClient.GetInstanceByName(serviceProvider, httpClientName);
53+
54+
if (!apiClientName.IsNullOrEmpty())
55+
{
56+
SetBaseAddress(apiClientName);
57+
}
58+
}
59+
60+
internal ApiClient(IServiceProvider serviceProvider, string apiClientName)
61+
{
62+
SenparcHttpClient = serviceProvider.GetService<SenparcHttpClient>();
63+
SetBaseAddress(apiClientName);
64+
}
65+
66+
private void SetBaseAddress(string apiClientName)
67+
{
68+
SenparcHttpClient.Client.BaseAddress = new($"https+http://{apiClientName}");
69+
}
70+
}
71+
72+
/// <summary>
73+
/// ApiClientHelper, set ApiClient parameters and get ApiClient object
74+
/// </summary>
75+
public sealed class ApiClientHelper
76+
{
77+
private readonly IServiceProvider _serviceProvider;
78+
79+
public ApiClientHelper(IServiceProvider serviceProvider)
80+
{
81+
_serviceProvider = serviceProvider;
82+
}
83+
84+
/// <summary>
85+
/// Use an apiClientName to get the ApiClient object
86+
/// </summary>
87+
/// <param name="apiClientName"></param>
88+
/// <returns></returns>
89+
public ApiClient ConnectApiClient(string apiClientName)
90+
{
91+
var apiClient = new ApiClient(_serviceProvider, apiClientName);
92+
return apiClient;
93+
}
94+
95+
/// <summary>
96+
/// Use an httpClientName and an apiClientName(optional) to get the ApiClient object
97+
/// </summary>
98+
/// <param name="httpClientName"></param>
99+
/// <param name="apiClientName"></param>
100+
/// <returns></returns>
101+
public ApiClient ConnectHttpClient(string httpClientName, string apiClientName = null)
102+
{
103+
var apiClient = new ApiClient(_serviceProvider, httpClientName, apiClientName);
104+
return apiClient;
105+
}
106+
}
107+
}
108+
#endif

0 commit comments

Comments
 (0)