Compare commits

..
5 Commits
6 changed files with 99 additions and 38 deletions
+2 -10
View File
@@ -46,23 +46,15 @@ public class SimApiBaseResponse(int code = 200, string message = "成功")
} }
/// <summary> /// <summary>
/// 动态内容分页 /// 分页内容返回
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
public class SimApiBasePageResponse<T>() : SimApiBaseResponse public class PageResponse<T>
{ {
public T? List { get; set; } public T? List { get; set; }
public int Page { get; set; } = 1; public int Page { get; set; } = 1;
public int Count { get; set; } = 20; public int Count { get; set; } = 20;
public int Total { get; set; } public int Total { get; set; }
public SimApiBasePageResponse(T list, int page, int count, int total) : this()
{
List = list;
Page = page;
Count = count;
Total = total;
}
} }
/// <summary> /// <summary>
+27 -8
View File
@@ -4,10 +4,11 @@ using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Json; using System.Net.Http.Json;
using SimApi.Communications; using SimApi.Communications;
using SimApi.Exceptions;
namespace SimApi.Helpers; namespace SimApi.Helpers;
public class SimApiHttpClient(string? appId, string appKey) public class SimApiHttpClient(string? appId, string appKey, bool debug = false)
{ {
public string Server { get; init; } = string.Empty; public string Server { get; init; } = string.Empty;
public string SignName { get; init; } = "sign"; public string SignName { get; init; } = "sign";
@@ -16,7 +17,6 @@ public class SimApiHttpClient(string? appId, string appKey)
public string? AppIdName { get; init; } = "appId"; public string? AppIdName { get; init; } = "appId";
public string[] SignFields { get; init; } = []; public string[] SignFields { get; init; } = [];
public T? SignQuery<T>(string url, object? body = null, Dictionary<string, string>? queries = null) public T? SignQuery<T>(string url, object? body = null, Dictionary<string, string>? queries = null)
{ {
url = Server + url; url = Server + url;
@@ -37,9 +37,7 @@ public class SimApiHttpClient(string? appId, string appKey)
.Aggregate(path, (current, q) => current + $"&{q.Key}={q.Value}"); .Aggregate(path, (current, q) => current + $"&{q.Key}={q.Value}");
} }
var http = new HttpClient(); return Query<T>(path, body);
var resp = http.PostAsJsonAsync(path, body).Result;
return resp.Content.ReadFromJsonAsync<T>().Result;
} }
public T? AesQuery<T>(string url, object body) public T? AesQuery<T>(string url, object body)
@@ -54,9 +52,7 @@ public class SimApiHttpClient(string? appId, string appKey)
{ {
Data = SimApiAesUtil.Encrypt(SimApiUtil.Json(body), appKey) Data = SimApiAesUtil.Encrypt(SimApiUtil.Json(body), appKey)
}; };
var http = new HttpClient(); return Query<T>(url, req);
var resp = http.PostAsJsonAsync(url, req).Result;
return resp.Content.ReadFromJsonAsync<T>().Result;
} }
public T? AesSignQuery<T>(string url, object body, Dictionary<string, string>? queries = null) public T? AesSignQuery<T>(string url, object body, Dictionary<string, string>? queries = null)
@@ -67,4 +63,27 @@ public class SimApiHttpClient(string? appId, string appKey)
}; };
return SignQuery<T>(url, req, queries); return SignQuery<T>(url, req, queries);
} }
private T? Query<T>(string url, object? req)
{
var http = new HttpClient();
if (debug)
{
Console.WriteLine($"[HTTPCLIENT请求] {url}\n{SimApiUtil.Json(req)}\n");
}
var resp = http.PostAsJsonAsync(url, req).Result;
if (debug)
{
Console.WriteLine($"[HTTPCLIENT响应] {resp.Content.ReadAsStringAsync().Result}\n");
}
var res = resp.Content.ReadFromJsonAsync<SimApiBaseResponse<T>>().Result;
if (res == null)
{
throw new SimApiException(500, "请求发生错误");
}
return res.Code != 200 ? throw new SimApiException(res.Code, res.Message) : res.Data;
}
} }
+2 -2
View File
@@ -23,8 +23,8 @@
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="10.0.1" /> <PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="10.0.1" />
<PackageReference Include="Minio" Version="7.0.0" /> <PackageReference Include="Minio" Version="7.0.0" />
<PackageReference Include="MQTTnet" Version="5.0.1.1416"/> <PackageReference Include="MQTTnet" Version="5.0.1.1416"/>
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="10.0.1" /> <PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="10.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.0.1" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.1.0" />
</ItemGroup> </ItemGroup>
<ProjectExtensions> <ProjectExtensions>
<MonoDevelop> <MonoDevelop>
+41 -4
View File
@@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@@ -123,11 +124,47 @@ public static class SimApiExtensions
}); });
} }
x.CustomSchemaIds(type => type.FullName?.Replace("+", ".")); x.CustomSchemaIds(type =>
{
string GetSimpleTypeName(Type t)
{
if (t.IsArray)
{
var elementType = t.GetElementType();
return $"{GetSimpleTypeName(elementType)}[]";
}
if (t.IsPrimitive || t == typeof(string) || t == typeof(DateTime) || t == typeof(Guid))
{
return t.Name switch
{
"String" => "string",
"Int32" => "int",
"Int64" => "long",
"Boolean" => "boolean",
"DateTime" => "DateTime",
"Guid" => "Guid",
_ => t.Name
};
}
return t.Name;
}
if (!type.IsGenericType) return GetSimpleTypeName(type);
var baseName = type.GetGenericTypeDefinition().Name.Split('`')[0];
var genericArgs = type.GetGenericArguments()
.Select(GetSimpleTypeName)
.ToArray();
return genericArgs.Length > 0
? $"{baseName}<{string.Join(",", genericArgs)}>"
: baseName;
});
x.OperationFilter<SimApiResponseOperationFilter>(); x.OperationFilter<SimApiResponseOperationFilter>();
x.OperationFilter<SimApiSignOperationFilter>(); x.OperationFilter<SimApiSignOperationFilter>();
x.OperationFilter<AesBodyOperationFilter>(); x.OperationFilter<AesBodyOperationFilter>();
x.SchemaFilter<GlobalDynamicObjectSchemaFilter>(); x.SchemaFilter<GlobalDynamicObjectSchemaFilter>();
x.DocumentFilter<RemoveEmptyTagsFilter>();
if (simApiOptions.EnableSimApiAuth) if (simApiOptions.EnableSimApiAuth)
{ {
x.OperationFilter<SimApiAuthOperationFilter>(); x.OperationFilter<SimApiAuthOperationFilter>();
@@ -157,11 +194,12 @@ public static class SimApiExtensions
switch (auth) switch (auth)
{ {
case "SimApiAuth": case "SimApiAuth":
x.AddSecurityDefinition("HeaderToken", x.AddSecurityDefinition("SimApiAuth",
new OpenApiSecurityScheme new OpenApiSecurityScheme
{ {
Name = "Token", Name = "Token",
In = ParameterLocation.Header In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
}); });
break; break;
case "ClientCredentials": case "ClientCredentials":
@@ -392,7 +430,6 @@ public static class SimApiExtensions
x.SwaggerEndpoint($"/swagger/{group.Id}.json", name: group.Name); x.SwaggerEndpoint($"/swagger/{group.Id}.json", name: group.Name);
} }
x.EnableValidator();
x.SupportedSubmitMethods(docOptions.SupportedMethod); x.SupportedSubmitMethods(docOptions.SupportedMethod);
x.DisplayRequestDuration(); x.DisplayRequestDuration();
}); });
+25
View File
@@ -0,0 +1,25 @@
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Linq;
namespace SimApi.SwaggerFilters;
public class RemoveEmptyTagsFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
// 步骤1:收集所有有接口的 Tag 名称
var tagsWithOperations = swaggerDoc.Paths.Values
.SelectMany(path => path.Operations.Values)
.SelectMany(op => op.Tags.Select(t => t.Name))
.Distinct()
.ToList();
// 步骤2:移除无接口的空 Tag
var emptyTags = swaggerDoc.Tags.Where(t => !tagsWithOperations.Contains(t.Name)).ToList();
foreach (var tag in emptyTags)
{
swaggerDoc.Tags.Remove(tag);
}
}
}
+2 -14
View File
@@ -19,22 +19,10 @@ namespace SimApi.SwaggerFilters
// 控制器上有 [SimApiAuth](继承到所有方法) // 控制器上有 [SimApiAuth](继承到所有方法)
context.MethodInfo.DeclaringType?.GetCustomAttributes<SimApiAuthAttribute>(true).Any() == true; context.MethodInfo.DeclaringType?.GetCustomAttributes<SimApiAuthAttribute>(true).Any() == true;
if (!requiresAuth) return; if (!requiresAuth) return;
// 关键修复:正确构造 OpenApiSecuritySchemeReference(匹配键类型要求)
var securitySchemeRef = new OpenApiSecuritySchemeReference(
referenceId: "SimApiAuth", // 必须与 AddSecurityDefinition 的 ID 一致
hostDocument: null,
externalResource: null
);
// 给 Security 赋值(确保键类型是 OpenApiSecuritySchemeReference
operation.Security ??= new List<OpenApiSecurityRequirement>(); operation.Security ??= new List<OpenApiSecurityRequirement>();
operation.Security.Add(new OpenApiSecurityRequirement operation.Security.Add(new OpenApiSecurityRequirement()
{ {
{ { new OpenApiSecuritySchemeReference("SimApiAuth", context.Document), [] }
securitySchemeRef,
[]
}
}); });
} }
} }