Merge pull request '🍓 feat(HttpRemote): 拆分远程请求配置到业务层' (#420) from jasondom/Admin.NET.Pro:v2-1 into v2
Reviewed-on: https://code.adminnet.top/Admin.NET/Admin.NET.Pro/pulls/420
This commit is contained in:
commit
d3ceb0ad1e
@ -31,6 +31,13 @@
|
|||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Remove="Configuration\HttpRemotes.*.json" />
|
||||||
|
<Content Include="Configuration\HttpRemotes.*.json">
|
||||||
|
<DependentUpon>HttpRemotes.json</DependentUpon>
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="wwwroot\**\*">
|
<Content Include="wwwroot\**\*">
|
||||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
|
||||||
|
|
||||||
|
"HttpProxy": { // 代理配置
|
||||||
|
"Encrypt": false,
|
||||||
|
"MaxRetries": 3,
|
||||||
|
"Address": "http://route.xiongmaodaili.com/xxxxxxxx",
|
||||||
|
"Account": "",
|
||||||
|
"Password": ""
|
||||||
|
},
|
||||||
|
"HttpRemotes": {
|
||||||
|
"WorkWeixin": { // 企业微信
|
||||||
|
"EnabledLog": true,
|
||||||
|
"UseCookies": false,
|
||||||
|
"EnabledProxy": false,
|
||||||
|
"HttpName": "WORK_WEIXIN",
|
||||||
|
"BaseAddress": "https://qyapi.weixin.qq.com",
|
||||||
|
"Headers": {
|
||||||
|
"User-Agent": "WORK_WEIXIN"
|
||||||
|
},
|
||||||
|
"Timeout": 60
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,28 +1,14 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
|
"$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
|
||||||
|
|
||||||
"HttpRemotes": {
|
"HttpProxy": { // 代理配置
|
||||||
"Proxy": { // 代理配置
|
|
||||||
"Encrypt": false,
|
"Encrypt": false,
|
||||||
"MaxRetries": 3,
|
"MaxRetries": 3,
|
||||||
"Address": "http://route.xiongmaodaili.com/xxxxxxxx",
|
"Address": "http://route.xiongmaodaili.com/xxxxxxxx",
|
||||||
"Account": "",
|
"Account": "",
|
||||||
"Password": ""
|
"Password": ""
|
||||||
},
|
},
|
||||||
"HttpBin": { // 获取Ip
|
"HttpRemotes": {
|
||||||
"EnabledLog": true,
|
|
||||||
"UseCookies": false,
|
|
||||||
"EnabledProxy": false,
|
|
||||||
"HttpName": "HTTP_BIN",
|
|
||||||
"BaseAddress": "http://httpbin.org/ip",
|
|
||||||
"Headers": {
|
|
||||||
"Connection": "Keep-Alive",
|
|
||||||
"Sec-Fetch-Mode": "cors",
|
|
||||||
"Sec-Fetch-Site": "same-origin",
|
|
||||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
|
|
||||||
},
|
|
||||||
"Timeout": 5
|
|
||||||
},
|
|
||||||
"WorkWeixin": { // 企业微信
|
"WorkWeixin": { // 企业微信
|
||||||
"EnabledLog": true,
|
"EnabledLog": true,
|
||||||
"UseCookies": false,
|
"UseCookies": false,
|
||||||
|
|||||||
20
Admin.NET/Admin.NET.Application/Option/HttpRemotesOptions.cs
Normal file
20
Admin.NET/Admin.NET.Application/Option/HttpRemotesOptions.cs
Normal 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; }
|
||||||
|
}
|
||||||
@ -17,7 +17,7 @@ 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>();
|
var options = App.GetConfig<object>("HttpRemotes") ?? throw new Exception("未正确配置HttpRemotes.json");
|
||||||
foreach (var prop in options.GetType().GetProperties())
|
foreach (var prop in options.GetType().GetProperties())
|
||||||
{
|
{
|
||||||
if (prop.GetValue(options) is not HttpRemoteItem opt) continue;
|
if (prop.GetValue(options) is not HttpRemoteItem opt) continue;
|
||||||
@ -47,3 +47,44 @@ public static class HttpRemotesExtension {
|
|||||||
return HttpLoggingHandler.SetRemoteApiAttr(builder, httpName, attr);
|
return HttpLoggingHandler.SetRemoteApiAttr(builder, httpName, attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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; }
|
||||||
|
}
|
||||||
@ -23,15 +23,16 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
|
|||||||
private readonly SysConfigService _sysConfigService;
|
private readonly SysConfigService _sysConfigService;
|
||||||
private readonly IEventPublisher _eventPublisher;
|
private readonly IEventPublisher _eventPublisher;
|
||||||
|
|
||||||
public HttpLoggingHandler(IEventPublisher eventPublisher, SysConfigService sysConfigService, IOptions<HttpRemotesOptions> options)
|
public HttpLoggingHandler(IEventPublisher eventPublisher, SysConfigService sysConfigService)
|
||||||
{
|
{
|
||||||
_eventPublisher = eventPublisher;
|
_eventPublisher = eventPublisher;
|
||||||
HttpRemotesOptions httpRemotesOptions = options.Value;
|
|
||||||
_sysConfigService = sysConfigService;
|
_sysConfigService = sysConfigService;
|
||||||
_enabledLogMap = typeof(HttpRemotesOptions).GetProperties()
|
|
||||||
|
var options = App.GetConfig<object>("HttpRemotes") ?? throw new Exception("未正确配置HttpRemotes.json");
|
||||||
|
_enabledLogMap = options.GetType().GetProperties()
|
||||||
.Where(u => u.PropertyType == typeof(HttpRemoteItem))
|
.Where(u => u.PropertyType == typeof(HttpRemoteItem))
|
||||||
.ToDictionary(u => u.GetValue(httpRemotesOptions) is HttpRemoteItem opt ? opt.HttpName : "",
|
.ToDictionary(u => u.GetValue(options) is HttpRemoteItem opt ? opt.HttpName : "",
|
||||||
u => u.GetValue(httpRemotesOptions) is HttpRemoteItem { EnabledLog: true });
|
u => u.GetValue(options) is HttpRemoteItem { EnabledLog: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
|
||||||
|
|||||||
38
Admin.NET/Admin.NET.Core/Option/HttpProxyOptions.cs
Normal file
38
Admin.NET/Admin.NET.Core/Option/HttpProxyOptions.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||||
|
//
|
||||||
|
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||||
|
//
|
||||||
|
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||||
|
|
||||||
|
namespace Admin.NET.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 远程请求代理配置
|
||||||
|
/// </summary>
|
||||||
|
public sealed class HttpProxyOptions : IConfigurableOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 是否加密
|
||||||
|
/// </summary>
|
||||||
|
public bool Encrypt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 最大重试次数
|
||||||
|
/// </summary>
|
||||||
|
public string MaxRetries { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 代理服务器地址
|
||||||
|
/// </summary>
|
||||||
|
public string Address { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 代理服务器认证账号
|
||||||
|
/// </summary>
|
||||||
|
public string Account { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 代理服务器认证账号密码
|
||||||
|
/// </summary>
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
@ -1,100 +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 HttpProxyOption Proxy { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取Ip地址接口
|
|
||||||
/// </summary>
|
|
||||||
public HttpRemoteItem HttpBin { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 企业微信接口配置
|
|
||||||
/// </summary>
|
|
||||||
public HttpRemoteItem WorkWeixin { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 代理配置
|
|
||||||
/// </summary>
|
|
||||||
public class HttpProxyOption
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 是否加密
|
|
||||||
/// </summary>
|
|
||||||
public bool Encrypt { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 最大重试次数
|
|
||||||
/// </summary>
|
|
||||||
public string MaxRetries { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 代理服务器地址
|
|
||||||
/// </summary>
|
|
||||||
public string Address { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 代理服务器认证账号
|
|
||||||
/// </summary>
|
|
||||||
public string Account { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 代理服务器认证账号密码
|
|
||||||
/// </summary>
|
|
||||||
public string Password { 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; }
|
|
||||||
}
|
|
||||||
@ -4,6 +4,7 @@
|
|||||||
//
|
//
|
||||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||||
|
|
||||||
|
using Admin.NET.Application;
|
||||||
using Admin.NET.Core;
|
using Admin.NET.Core;
|
||||||
using AspNetCoreRateLimit;
|
using AspNetCoreRateLimit;
|
||||||
using Furion;
|
using Furion;
|
||||||
|
|||||||
@ -37,7 +37,7 @@ namespace @Model.NameSpace;
|
|||||||
public partial class @(@Model.ClassName)Service : IDynamicApiController, ITransient
|
public partial class @(@Model.ClassName)Service : IDynamicApiController, ITransient
|
||||||
{
|
{
|
||||||
private readonly SysCacheService _sysCacheService;//默认CacheService
|
private readonly SysCacheService _sysCacheService;//默认CacheService
|
||||||
private readonly UserSession _userManager;//默认用户管理
|
private readonly UserManager _userManager;//默认用户管理
|
||||||
private readonly IEventPublisher _eventPublisher;//默认事件总线
|
private readonly IEventPublisher _eventPublisher;//默认事件总线
|
||||||
private readonly SqlSugarRepository<@(@Model.ClassName)> _@(@Model.LowerClassName)Rep;
|
private readonly SqlSugarRepository<@(@Model.ClassName)> _@(@Model.LowerClassName)Rep;
|
||||||
@foreach (var column in Model.TableField){
|
@foreach (var column in Model.TableField){
|
||||||
@ -51,7 +51,7 @@ public partial class @(@Model.ClassName)Service : IDynamicApiController, ITransi
|
|||||||
|
|
||||||
public @(@Model.ClassName)Service(SqlSugarRepository<@(@Model.ClassName)> @(@Model.LowerClassName)Rep
|
public @(@Model.ClassName)Service(SqlSugarRepository<@(@Model.ClassName)> @(@Model.LowerClassName)Rep
|
||||||
,SysCacheService sysCacheService
|
,SysCacheService sysCacheService
|
||||||
, UserSession userManager
|
, UserManager userManager
|
||||||
,IEventPublisher eventPublisher
|
,IEventPublisher eventPublisher
|
||||||
@foreach (var column in Model.TableField){
|
@foreach (var column in Model.TableField){
|
||||||
if(@column.EffectType == "ForeignKey"||@column.EffectType == "ApiTreeSelector"){
|
if(@column.EffectType == "ForeignKey"||@column.EffectType == "ApiTreeSelector"){
|
||||||
|
|||||||
@ -21,9 +21,10 @@ namespace Admin.NET.Plugin.WorkWeixin;
|
|||||||
public class WorkWxBaseService(
|
public class WorkWxBaseService(
|
||||||
SysCacheService sysCacheService,
|
SysCacheService sysCacheService,
|
||||||
SysConfigService sysConfigService,
|
SysConfigService sysConfigService,
|
||||||
IHttpRemoteService httpRemoteService,
|
IHttpRemoteService httpRemoteService) : ITransient
|
||||||
IOptions<HttpRemotesOptions> options) : ITransient
|
|
||||||
{
|
{
|
||||||
|
private static readonly Lazy<HttpRemoteItem> _options = new(() => App.GetConfig<HttpRemoteItem>("HttpRemotes.WorkWeixin"));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取企业微信接口凭证
|
/// 获取企业微信接口凭证
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -54,15 +55,14 @@ public class WorkWxBaseService(
|
|||||||
/// <returns>返回结果</returns>
|
/// <returns>返回结果</returns>
|
||||||
public async Task<R> SendAsync<T, R>(T input) where R : BaseWorkWxOutput
|
public async Task<R> SendAsync<T, R>(T input) where R : BaseWorkWxOutput
|
||||||
{
|
{
|
||||||
var opt = options.Value.WorkWeixin;
|
if (_options.Value == null || string.IsNullOrWhiteSpace(_options.Value.BaseAddress)) throw Oops.Oh("[企业微信] 服务配置缺失");
|
||||||
if (opt == null || string.IsNullOrWhiteSpace(opt.BaseAddress)) throw Oops.Oh("[企业微信] 服务配置缺失");
|
|
||||||
|
|
||||||
var attr = typeof(T).GetCustomAttribute<HttpRemoteApiAttribute>();
|
var attr = typeof(T).GetCustomAttribute<HttpRemoteApiAttribute>();
|
||||||
if (attr == null || string.IsNullOrWhiteSpace(attr.Action as string))
|
if (attr == null || string.IsNullOrWhiteSpace(attr.Action as string))
|
||||||
throw Oops.Oh("[企业微信] 接口入参未正确配置[HttpRemoteApi]特性");
|
throw Oops.Oh("[企业微信] 接口入参未正确配置[HttpRemoteApi]特性");
|
||||||
|
|
||||||
// 拼接请求地址,并设置token
|
// 拼接请求地址,并设置token
|
||||||
var url = opt.BaseAddress + $"/cgi-bin/{attr.Action}?";
|
var url = _options.Value.BaseAddress + $"/cgi-bin/{attr.Action}?";
|
||||||
if (input is AuthWorkWxInput)
|
if (input is AuthWorkWxInput)
|
||||||
{
|
{
|
||||||
// 重试3次
|
// 重试3次
|
||||||
@ -83,9 +83,9 @@ public class WorkWxBaseService(
|
|||||||
{
|
{
|
||||||
HttpMethodEnum.Get => await httpRemoteService.GetAsync(
|
HttpMethodEnum.Get => await httpRemoteService.GetAsync(
|
||||||
url + input.ToCustomJsonPropertyQueryString(),
|
url + input.ToCustomJsonPropertyQueryString(),
|
||||||
builder => builder.SetRemoteApiAttr(opt.HttpName, attr)),
|
builder => builder.SetRemoteApiAttr(_options.Value.HttpName, attr)),
|
||||||
HttpMethodEnum.Post => await httpRemoteService.PostAsync(url,
|
HttpMethodEnum.Post => await httpRemoteService.PostAsync(url,
|
||||||
builder => builder.SetRemoteApiAttr(opt.HttpName, attr)
|
builder => builder.SetRemoteApiAttr(_options.Value.HttpName, attr)
|
||||||
.SetContent(new StringContent(JSON.Serialize(input, CustomJsonPropertyConverter.Options), Encoding.UTF8, "application/json"))),
|
.SetContent(new StringContent(JSON.Serialize(input, CustomJsonPropertyConverter.Options), Encoding.UTF8, "application/json"))),
|
||||||
_ => throw Oops.Oh($"[企业微信] 不支持的请求方式:{attr.HttpMethod.ToString()}:({typeof(T).FullName})"),
|
_ => throw Oops.Oh($"[企业微信] 不支持的请求方式:{attr.HttpMethod.ToString()}:({typeof(T).FullName})"),
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user