使用.NET6实现动态API
程序员文章站
2022-06-26 17:36:02
目录开发环境项目地址项目目标编码约定核心代码使用示例apilite是基于.net6直接将service层生成动态api路由,可以不用添加controller,支持模块插件化,在项目开发中能够提高工作效...
apilite是基于.net6直接将service层生成动态api路由,可以不用添加controller,支持模块插件化,在项目开发中能够提高工作效率,降低代码量。
开发环境
- .net sdk 6.0.100-rc.2.21505.57
- vs2022 preview 7.0
项目地址
github: https://github.com/known/apilite
项目目标
- 根据service动态生成api
- 支持自定义路由模板(通过route特性定义)
- 支持模块插件化
- 支持不同模块,相同service名称的路由(命名空间需要有3级以上,例如:com.mod.xxx)
- 自动根据方法名称判断请求方式,get开头的方法名为get请求,其他为post请求
编码约定
- 模块类库必须包含继承imodule接口的类
- 需要生成api的service必须继承iservice接口
- get请求的方法必须以get开头
核心代码
主要是apifeatureprovider和apiconvention这两个自定义类来动态生成api,apifeatureprovider继承controllerfeatureprovider,覆写iscontroller方法,判断服务类型是否符合controller。apiconvention实现了iapplicationmodelconvention接口,实现动态添加action。下面是主要代码,完整代码请在github上下载。
static class serviceextension { internal static webapplicationbuilder addkapp(this webapplicationbuilder builder, action<appoption>? action = null) { var option = new appoption(); action?.invoke(option); ... adddynamicapi(mvcbuilder, option);//添加动态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,这样才能发现服务类 var assembly = item.gettype().assembly; m.applicationparts.add(new assemblypart(assembly)); } m.featureproviders.add(new apifeatureprovider()); }); builder.services.configure<mvcoptions>(o => { o.conventions.add(new apiconvention()); }); } } //判断服务类型是否为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); } } } ... //构造路由模板 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; } }
以上所述是小编给大家介绍的使用.net6实现动态api,希望对大家有所帮助。在此也非常感谢大家对网站的支持!