Skip to content

Commit 87f795e

Browse files
committed
WebApi v1.1 提供参数属性同步复制到动态 Api 的能力
1 parent 7414b8f commit 87f795e

File tree

3 files changed

+111
-11
lines changed

3 files changed

+111
-11
lines changed

Sample/Senparc.CO2NET.Sample.net6/Services/ApiBindTestService.cs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.Extensions.DependencyInjection;
44
using Swashbuckle.AspNetCore.Annotations;
55
using System;
6+
using System.ComponentModel;
67
using System.Diagnostics;
78
using System.Linq;
89
using System.Reflection;
@@ -383,7 +384,8 @@ public string RewriteApiBind(string name = "Senparc", int value = 920)
383384
/// 静态类,自动继承 class 配置
384385
/// </summary>
385386
/// <returns></returns>
386-
public static string StaticMethod() {
387+
public static string StaticMethod()
388+
{
387389
return "ClassCover.StaticMethod";
388390
}
389391
}
@@ -488,4 +490,60 @@ public MyTestAttribute(string name)
488490
}
489491
}
490492

493+
494+
/// <summary>
495+
/// 参数带 Attribute
496+
/// </summary>
497+
[ApiController]
498+
public class ParameterAttribute
499+
{
500+
/// <summary>
501+
/// 参数带 Attribute 测试
502+
/// </summary>
503+
/// <param name="requestData"></param>
504+
/// <returns></returns>
505+
[ApiBind(ApiRequestMethod = WebApi.ApiRequestMethod.Post)]
506+
public static string ParameterAttributeTest([FromBody]RequestData requestData1)
507+
{
508+
/*
509+
* 可用 PostMan 等工具测试:
510+
* curl --location --request POST 'https://localhost:44351/api/Senparc.CO2NET.Sample/ParameterAttribute/CO2NET.Sample_ParameterAttribute.ParameterAttributeTest' \
511+
--header 'Content-Type: application/json' \
512+
--data-raw '{
513+
"UserName": "SenparcCoreAdmin96",
514+
"Password": "743e815e2"
515+
}'
516+
*
517+
* 结果:SenparcCoreAdmin96:743e815e2 -- 2021/11/22 21:11:14 +08:00
518+
*/
519+
520+
return $"{requestData1.UserName}:{requestData1.Password} -- {SystemTime.Now}";
521+
}
522+
523+
524+
}
525+
public class RequestData
526+
{
527+
public string UserName { get; set; }
528+
public string Password { get; set; }
529+
}
530+
531+
[ApiController]
532+
[Route("[controller]")]
533+
public class NormalApi : ControllerBase
534+
{
535+
536+
[HttpPost("login")]
537+
public IActionResult Login([FromBody]RequestData request)
538+
{
539+
return Content($"{request.UserName}:{request.Password} -- {SystemTime.Now}");
540+
}
541+
542+
[HttpGet("login2")]
543+
public IActionResult Login2(RequestData request)
544+
{
545+
return Content($"{request.UserName}:{request.Password}");
546+
}
547+
}
548+
491549
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFrameworks>netstandard2.1;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
4-
<Version>1.0</Version>
4+
<Version>1.1</Version>
55
<LangVersion>latest</LangVersion>
66
<AssemblyName>Senparc.CO2NET.WebApi</AssemblyName>
77
<RootNamespace>Senparc.CO2NET.WebApi</RootNamespace>
@@ -30,7 +30,8 @@
3030
v0.2.5.7 添加 ForbiddenExternalAccess 参数,设置是否允许外部访问
3131
v0.2.6 添加 WebApiEngineOptions
3232
v0.2.8 提供 .NET Standard 2.1 版本
33-
</PackageReleaseNotes>
33+
v1.1 提供参数属性同步复制到动态 Api 的能力
34+
</PackageReleaseNotes>
3435
</PropertyGroup>
3536
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
3637
<OutputPath>..\BuildOutPut</OutputPath>
@@ -48,6 +49,7 @@
4849
<ItemGroup>
4950
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
5051
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.2.3" />
52+
<!--<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />-->
5153
</ItemGroup>
5254
<ItemGroup>
5355
<ProjectReference Include="..\Senparc.CO2NET.AspNet\Senparc.CO2NET.AspNet.csproj" />

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

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@
77
88
创建标识:Senparc - 20210627
99
10+
修改标识:Senparc - 20211122
11+
修改描述:v1.1 提供参数属性同步复制到动态 Api 的能力
12+
1013
----------------------------------------------------------------*/
1114

1215
using Microsoft.AspNetCore.Mvc;
16+
using Microsoft.AspNetCore.Mvc.ModelBinding;
1317
using Senparc.CO2NET.WebApi.ActionFilters;
1418
using Swashbuckle.AspNetCore.Annotations;
1519
using System;
@@ -324,7 +328,6 @@ private async Task BuildApiMethodForOneThread(IGrouping<string, KeyValuePair<str
324328
}
325329

326330
//叠加类和特性的方法
327-
328331
foreach (var item in customAttrs)
329332
{
330333
if (item.AttributeType == _typeOfApiBind)
@@ -360,27 +363,64 @@ private async Task BuildApiMethodForOneThread(IGrouping<string, KeyValuePair<str
360363
//setPropMthdBldr.SetReturnType(apiMethodInfo.ReturnType);
361364

362365
//设置参数
363-
var boundType = false;
366+
var boundSourceMetadata = false;//参数使用了[FromBody]等特性标记
367+
var boundClassType = false;//参数中已经绑定了 class 复杂类型
364368
//定义其他参数
365369
for (int i = 0; i < parameters.Length; i++)
366370
{
367371
var p = parameters[i];
368372
ParameterBuilder pb = setPropMthdBldr.DefineParameter(i + 1/*从1开始,0为返回值*/, p.Attributes, p.Name);
369373
//处理参数,反之出现复杂类型的参数,抛出异常:InvalidOperationException: Action 'WeChat_OfficialAccountController.CardApi_GetOrderList (WeixinApiAssembly)' has more than one parameter that was specified or inferred as bound from request body. Only one parameter per action may be bound from body. Inspect the following parameters, and use 'FromQueryAttribute' to specify bound from query, 'FromRouteAttribute' to specify bound from route, and 'FromBodyAttribute' for parameters to be bound from body:
370-
if (p.ParameterType.IsClass)
374+
375+
376+
boundSourceMetadata = boundSourceMetadata || typeof(IBindingSourceMetadata).IsAssignableFrom(p.ParameterType);
377+
378+
//复制添加单个参数上的所有特性
379+
try
371380
{
372-
if (boundType == false)
381+
var paramAttrs = p.CustomAttributes;// CustomAttributeData.GetCustomAttributes(p.ParameterType).ToList();
382+
foreach (var item in paramAttrs)
373383
{
374-
//第一个绑定,可以不处理
375-
boundType = true;
384+
var attrBuilder = new CustomAttributeBuilder(item.Constructor, item.ConstructorArguments.Select(z => z.Value).ToArray());
385+
pb.SetCustomAttribute(attrBuilder);
376386
}
377-
else
387+
}
388+
catch (Exception)
389+
{
390+
//TODO:收集错误信息
391+
//throw;
392+
}
393+
394+
try
395+
{
396+
if (p.ParameterType.IsClass && !boundClassType)
378397
{
379-
//第二个开始使用标签
398+
boundClassType = true;//第一个绑定,可以不处理
399+
}
400+
else if (boundClassType && !boundSourceMetadata)
401+
{
402+
//第二个开始使用标签 TODO:可以自定义更多的类型
380403
var tFromQuery = typeof(FromQueryAttribute);
381404
pb.SetCustomAttribute(new CustomAttributeBuilder(tFromQuery.GetConstructor(new Type[0]), new object[0]));
382405
}
406+
407+
//if (!boundSourceMetadata && p.ParameterType.IsClass)
408+
//{
409+
// if (boundClassType == false)
410+
// {
411+
412+
// }
413+
// else
414+
// {
415+
416+
// }
417+
//}
383418
}
419+
catch (Exception)
420+
{
421+
//throw;
422+
}
423+
384424
try
385425
{
386426
//设置默认值

0 commit comments

Comments
 (0)