使用 .NET6 打造動態(tài) API
前言
ApiLite是直接將Service層自動生成api路由,可以不用添加Controller,支持模塊插件化,在項目開發(fā)中能夠提高工作效率,降低代碼量。
開發(fā)環(huán)境
.NET SDK 6.0.100-rc.2.21505.57 VS2022 Preview 7.0
地址
GitHub: https://github.com/known/ApiLite
目標
根據(jù)Service動態(tài)生成api 支持自定義路由模板(通過Route特性定義) 支持模塊插件化 支持不同模塊,相同Service名稱的路由(命名空間需要有3級以上,例如:Com.Mod.XXX) 自動根據(jù)方法名稱判斷請求方式,Get開頭的方法名為GET請求,其他為POST請求
編碼約定
模塊類庫必須包含繼承IModule接口的類 需要生成api的Service必須繼承IService接口 GET請求的方法必須以Get開頭
核心代碼
主要是ApiFeatureProvider和ApiConvention這兩個自定義類來動態(tài)生成api,ApiFeatureProvider繼承ControllerFeatureProvider,覆寫IsController方法,判斷服務(wù)類型是否符合Controller。
ApiConvention實現(xiàn)了IApplicationModelConvention接口,動態(tài)添加Action。
下面是主要代碼,完整代碼請在GitHub上下載。
static?class?ServiceExtension
{
????internal?static?WebApplicationBuilder?AddKApp(this?WebApplicationBuilder?builder,?Action??action?=?null )
????{
????????var?option?=?new?AppOption();
????????action?.Invoke(option);
????????...
????????AddDynamicApi(mvcBuilder,?option);//添加動態(tài)api
????????return?builder;
????}
????private?static?void?AddDynamicApi(IMvcBuilder?builder,?AppOption?option)
????{
????????builder.ConfigureApplicationPartManager(m?=>
????????{
????????????m.ApplicationParts.Add(new?AssemblyPart(typeof(IService).Assembly));
????????????foreach?(var?item?in?option.Modules)
????????????{
????????????????item.Initialize();//初始化模塊
????????????????//將模塊添加到ApplicationParts,這樣才能發(fā)現(xiàn)服務(wù)類
????????????????var?assembly?=?item.GetType().Assembly;
????????????????m.ApplicationParts.Add(new?AssemblyPart(assembly));
????????????}
????????????m.FeatureProviders.Add(new?ApiFeatureProvider());
????????});
????????builder.Services.Configure(o?=>
????????{
????????????o.Conventions.Add(new?ApiConvention());
????????});
????}
????internal?static?WebApplication?UseKApp(this?WebApplication?app)
????{
????????...
????????return?app;
????}
}
//判斷服務(wù)類型是否為Controller
class?ApiFeatureProvider?:?ControllerFeatureProvider
{
????protected?override?bool?IsController(TypeInfo?typeInfo)
????{
????????if?(!typeof(IService).IsAssignableFrom(typeInfo)?||
????????????!typeInfo.IsPublic?||
????????????typeInfo.IsAbstract?||
????????????typeInfo.IsGenericType)
????????????return?false;
????????return?true;
????}
}
class?ApiConvention?:?IApplicationModelConvention
{
????public?void?Apply(ApplicationModel?application)
????{
????????foreach?(var?controller?in?application.Controllers)
????????{
????????????var?type?=?controller.ControllerType;
????????????if?(typeof(IService).IsAssignableFrom(type))
????????????{
????????????????ConfigureApiExplorer(controller);
????????????????ConfigureSelector(controller);
????????????}
????????}
????}
????...
????//構(gòu)造路由模板
????private?string?GetRouteTemplate(ActionModel?action)
????{
????????if?(action.Attributes?!=?null?&&?action.Attributes.Count?>?0)
????????{
????????????foreach?(var?item?in?action.Attributes)
????????????{
????????????????if?(item?is?RouteAttribute?attribute)
????????????????{
????????????????????return?attribute.Path;//返回自定義路由
????????????????}
????????????}
????????}
????????var?routeTemplate?=?new?StringBuilder();
????????//routeTemplate.Append("api");
????????var?names?=?action.Controller.ControllerType.Namespace.Split('.');
????????if?(names.Length?>?2)
????????{
????????????//支持不同模塊相同類名,添加命名空間模塊名作前綴
????????????routeTemplate.Append(names[^2]);
????????}
????????//?Controller
????????var?controllerName?=?action.Controller.ControllerName;
????????if?(controllerName.EndsWith("Service"))
????????????controllerName?=?controllerName[0..^7];
????????routeTemplate.Append($"/{controllerName}");
????????//?Action
????????var?actionName?=?action.ActionName;
????????if?(actionName.EndsWith("Async"))
????????????actionName?=?actionName[..^"Async".Length];
????????if?(!string.IsNullOrEmpty(actionName))
????????????routeTemplate.Append($"/{actionName}");
????????return?routeTemplate.ToString();
????}
}
使用示例
KHost.Run(args,?o?=>
{
????o.Modules.Add(new?TestModule());//添加模塊
});
class?TestModule?:?IModule
{
????public?void?Initialize()
????{
????}
}
public?class?TestService?:?IService
{
????public?string?GetName(string?name)
????{
????????return?$"Hello?{name}";
????}
????public?string?SaveData(string?data)
????{
????????return?$"{DateTime.Now:yyyy-MM-dd?HH:mm:ss}?{data}";
????}
????[Route("api/test")]
????public?string?GetCustMethod(string?id)
????{
????????return?id;
????}
}
轉(zhuǎn)自:known
鏈接:cnblogs.com/known/p/15499542.html
評論
圖片
表情
