- A+
所属分类:.NET技术
[QuickApi("hello/world")] public class MyApi : BaseQuickApi<Req,Rsp>{}
使用方式 :
dotnet add package Biwen.QuickApi dotnet add package Biwen.QuickApi.SourceGenerator
最后简简单单注册路由:
app.MapGenQuickApis("api");
Biwen.QuickApi 使用REPR风格写的minimalApi已经写完了, 最近看到道友们都玩SourceGen提升代码性能
,所以一鼓作气 自己也实现了一个 Biwen.QuickApi的 代码生成器版本 用以替换 代码中反射和dynamic带来的性能问题
Biwen.QuickApi下面这一段核心代码:
var req = await ((dynamic)api).ReqBinder.BindAsync(ctx.HttpContext!); //验证DTO if (req.RealValidator.Validate(req) is ValidationResult vresult && !vresult!.IsValid) { return Results.ValidationProblem(vresult.ToDictionary()); } try { //var result = await method.Invoke(api, new object[] { req! })!; var result = await ((dynamic)api)!.ExecuteAsync(req!); if (result is EmptyResponse) { return Results.Ok(); } if (result is ContentResponse content) { return Results.Content(content.Content); } Func<dynamic?, dynamic?> rspToExpandoObject = (rsp) => { if (rsp == null) return null; var type = rsp.GetType() as Type; var hasAlias = type!.GetProperties().Any(x => x.GetCustomAttribute<AliasAsAttribute>() != null); if (!hasAlias) { return rsp; } dynamic expandoObject = new ExpandoObject(); foreach (var prop in type.GetProperties()) { var alias = prop.GetCustomAttribute<AliasAsAttribute>(); ((IDictionary<string, object>)expandoObject)[alias != null ? alias.Name : prop.Name] = prop.GetValue(rsp); } return expandoObject; }; var expandoResult = rspToExpandoObject(result); return Results.Json(expandoResult, quickApiOptions?.JsonSerializerOptions); } catch (Exception ex) { var exceptionHandlers = ctx.HttpContext!.RequestServices.GetServices<IQuickApiExceptionHandler>(); //异常处理 foreach (var handler in exceptionHandlers) { await handler.HandleAsync(ex); } //默认处理 throw; }
Biwen.QuickApi的原理就是反射查找所有标记[QuickApi]特征的Api,然后批量注册服务&批量映射路由. 路由请求执行的方法体使用了上面那一段可能性能堪忧的代码. 如果用Gen的方式那么 上面一段代码就都变成了强类型引用 生成如下的结果 :
//绑定对象 var req = await api.ReqBinder.BindAsync(ctx.HttpContext!); //验证器 if (req.RealValidator.Validate(req) is ValidationResult vresult && !vresult!.IsValid) { return Results.ValidationProblem(vresult.ToDictionary()); } //执行请求 try { var result = await api.ExecuteAsync(req!); return Results.Json(result); } catch (Exception ex) { var exceptionHandlers = ctx.HttpContext!.RequestServices.GetServices<IQuickApiExceptionHandler>(); //异常处理 foreach (var handler in exceptionHandlers) { await handler.HandleAsync(ex); } //默认处理 throw; } ```这个就爽歪歪了 反射的问题没有了 动态类型也不见了 性能直接提升了 ! 最后 Gen的实现代码可以翻看. https://github.com/vipwan/Biwen.QuickApi 这里就不赘述了. 欢迎 star 交流 ~