[QuickApi("hello/world")] public class MyApi : BaseQuickApi<Req,Rsp>{} 使用方式 : dotnet add package Biwen.QuickApi dotnet add package Biwen.QuickApi.Sour ...
[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 交流 ~