欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

使用.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,希望对大家有所帮助。在此也非常感谢大家对网站的支持!

相关标签: .NET6 动态 API