Biwen.QuickApi代碼生成器功能上線


[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 交流 ~ 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章