利用委托与Lambada创建和调用webapi接口

前言 

 现在项目中用的是webapi,其中有以下问题:

      1.接口随着开发的增多逐渐增加相当庞大。

    2.接口调用时不好管理。

  以上是主要问题,对此就衍生了一个想法:

    如果每一个接口都一个配置文件来管理,每个配置文件能清晰表示处理接口文件,地址,参数,返回值,那么通过这个配置文件,就能很好的管理起来我们所有的webapi接口不是吗?

有了这个思路之后就有了以下的实现:

1.具体实现:

public void Build_Apis()
        {
            foreach (var ass in AppDomain.CurrentDomain.GetAssemblies().Where(a => a.GetCustomAttributes(typeof(QuickWebApiDllAttribute), true).Length > 0))
            {
                var vatt = ass.GetCustomAttribute<AssemblyFileVersionAttribute>();
                var tatt = ass.GetCustomAttribute<AssemblyTitleAttribute>();
                var datt = ass.GetCustomAttribute<QuickWebApiDllAttribute>();
                apis.Clear();
                var input_types = new List<Type>();
                foreach (var type in ass.GetTypes())
                {
                    var attr = type.GetCustomAttribute<QuickWebApiAttribute>();
                    if (attr != null)
                    {
                        WebApiNode api = new WebApiNode(datt.Domain) { Name = attr.name, Service = attr.service, Route = attr.route, Comment = attr.comment, Version = vatt.Version, Title = tatt.Title };
                        foreach (var mi in type.GetMethods())
                        {
                            var att = mi.GetCustomAttribute<QuickWebApiAttribute>();
                            if (att != null)
                            {
                                var act = new WebApiMethod() { Action = mi.Name, Code = att.service, Method = att.methodtype, Name = string.IsNullOrWhiteSpace(att.name) ? mi.Name : att.name, Comment = att.comment, OutputType = att.resultype };
                                foreach (var arg in mi.GetParameters())
                                {
                                    var mdatt = arg.ParameterType.GetCustomAttribute<DescriptionAttribute>();

                                    act.Params.Add(new WebApiMethodParam() { Name = arg.Name, TypeName = arg.ParameterType.Name, DefaultValue = string.IsNullOrWhiteSpace(arg.DefaultValue.ToString()) ? "无默认值" : arg.DefaultValue.ToString(), Desc = mdatt == null ? "" : mdatt.Description });
                                    if (arg.ParameterType.IsClass && arg.ParameterType != typeof(string))
                                    {
                                        if (!input_types.Exists(t => t.Name == arg.ParameterType.Name))
                                            input_types.Add(arg.ParameterType);
                                    }
                                }
                                if (!api.Methods.Exists(a => a.Action == act.Action))
                                    api.Methods.Add(act);

                                if (att.resultype != null && att.resultype.IsClass && att.resultype != typeof(string))
                                {
                                    if (!input_types.Exists(t => t.Name == att.resultype.Name))
                                        input_types.Add(att.resultype);
                                }
                            }
                        }
                        if (!apis.Exists(a => a.Service == api.Service))
                            apis.Add(api);
                    }
                }
                Build_Apids_Config(apis, datt.Name);
                Build_Apids_Doc(apis, datt.Name, input_types);
            }
        }

1.1:其中Build_Apis()方法,是系统根据,webapi接口描述,创建的对应的接口服务配置文件操作。

配置如下:

生成接口文件如下:

接口的实现

接下来只需你把xml文件引用到你要调用的站点下即可。

public string Load_Apis()
        {
            var files = System.IO.Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "apis_*.xml", System.IO.SearchOption.AllDirectories);
            apis.Clear();
            foreach (var path in files)
            {
                var jss = System.IO.File.ReadAllText(path);
                var _apis = Deserialize<List<WebApiNode>>(jss);
                if (_apis == null || _apis.Count == 0) continue;
                foreach (var api in _apis)
                {
                    if (apis.Exists(a => a.Service == api.Service)) continue;
                    apis.Add(api);
                }
            }
            return string.Format("service:{0}, action:{1}", apis.Count, apis.Sum(a => a.Methods.Count));
        }

1.2:其中Load_Apis()方式是在程序启动时加载webapi服务配置文件的操作,在这不再累述。

public class webapi<T, tresp> where tresp : class,new()
    {
        public webapi() { }
        public webapi(string service_prefix)
        {
            _service_prefix = service_prefix;
        }
        public webapi(long service_prefix_id)
        {
            _service_prefix = service_prefix_id.ToString();
        }

        protected string build_server(string srv)
        {
            return string.IsNullOrWhiteSpace(_service_prefix) ? srv : string.Format("{0}_{1}", _service_prefix, srv);
        }

        string _service_prefix;

        public result<tresp> invoke(Expression<Func<T, apiaction_l>> func, long args1)
        {
            return _invoke(func.Body, args1);
        }
        public result<tresp> invoke(Expression<Func<T, apiaction_ll>> func, long args1, long args2)
        {
            return _invoke(func.Body, args1, args2);
        }
        public result<tresp> invoke(Expression<Func<T, apiaction_li>> func, long args1, int args2)
        {
            return _invoke(func.Body, args1, args2);
        }
        public result<tresp> invoke(Expression<Func<T, apiaction_ls>> func, long args1, string args2)
        {
            return _invoke(func.Body, args1, args2);
        }

        //public result<tresp> invoke<treq>(Expression<Func<T, apiaction_s<treq>>> func, treq args1) where treq : struct
        //{
        //    return _invoke(func.Body, args1);
        //}
        public result<tresp> invoke(Expression<Func<T, apiaction_i>> func, int args1)
        {
            return _invoke(func.Body, args1);
        }
        public result<tresp> invoke(Expression<Func<T, apiaction_ii>> func, int args1, int args2)
        {
            return _invoke(func.Body, args1, args2);
        }
        public result<tresp> invoke(Expression<Func<T, apiaction_il>> func, int args1, long args2)
        {
            return _invoke(func.Body, args1, args2);
        }
        public result<tresp> invoke(Expression<Func<T, apiaction_is>> func, int args1, string args2)
        {
            return _invoke(func.Body, args1, args2);
        }
        public result<tresp> invoke(Expression<Func<T, apiaction_ss>> func, string args1, string args2)
        {
            return _invoke(func.Body, args1, args2);
        }
        public result<tresp> invoke(Expression<Func<T, apiaction_sss>> func, string args1, string args2, string args3)
        {
            return _invoke(func.Body, args1, args2, args3);
        }

        public result<tresp> invoke<treq>(Expression<Func<T, apiaction_o<treq>>> func, treq data) where treq : class,new()
        {
            if (data != null && data is String)
            {
                return _invoke(func.Body, data);
            }
            return _invoke_data<treq>(func.Body, data);
        }

        public result<tresp> invoke(Expression<Func<T, apiaction>> func)
        {
            return _invoke_data<object>(func.Body, null);
        }

        result<tresp> _invoke_data<treq>(Expression exp, treq data) where treq : class
        {
            var method = ((exp as UnaryExpression).Operand as MethodCallExpression);
            string code = ((method.Object as ConstantExpression).Value as MethodInfo).Name;

            foreach (var m in method.Arguments)
            {
                if (m.Type == typeof(T))
                {
                    var attr = m.Type.GetCustomAttribute<QuickWebApiAttribute>();
                    if (attr != null)
                    {
                        return new invoker(build_server(attr.service)).Excute<tresp>(code, data);
                    }
                }
            }
            return new result<tresp>(-1, "未能找到合适的api定义");
        }
        result<tresp> _invoke(Expression exp, params object[] args)
        {
            var method = ((exp as UnaryExpression).Operand as MethodCallExpression);
            string code = ((method.Object as ConstantExpression).Value as MethodInfo).Name;

            foreach (var m in method.Arguments)
            {
                if (m.Type == typeof(T))
                {
                    var attr = m.Type.GetCustomAttribute<QuickWebApiAttribute>();
                    StringBuilder sb = new StringBuilder();
                    var pis = m.Type.GetMethod(code).GetParameters();

                    for (int i = 0; i < pis.Length; i++)
                    {
                        sb.AppendFormat("{0}={1}&", pis[i].Name, args[i] is DateTime ? ((DateTime)args[i]).ToString("yyyy-MM-dd HH:mm:ss") : args[i]);
                    }

                    if (attr != null)
                    {
                        return new invoker(build_server(attr.service)).Excute<tresp>(code, sb.ToString());
                    }
                }
            }
            return new result<tresp>(-1, "未能找到合适的api定义");
        }
    }

1.3:其中  result<tresp> _invoke是:通过lambda对传递过来的委托,进行相应的反射操作。

其中委托定义如下:

 public delegate IHttpActionResult apiaction();
    public delegate IHttpActionResult apiaction_l(long args);
    public delegate IHttpActionResult apiaction_ll(long args1, long args2);
    public delegate IHttpActionResult apiaction_li(long args1, int arg2);
    public delegate IHttpActionResult apiaction_ls(long args1, string args2);
    public delegate IHttpActionResult apiaction_i(int args1);
    public delegate IHttpActionResult apiaction_ii(int args1, int args2);
    public delegate IHttpActionResult apiaction_is(int args1, string args2);
    public delegate IHttpActionResult apiaction_il(int args1, long args2);
    public delegate IHttpActionResult apiaction_si(string args1, int args2);
    public delegate IHttpActionResult apiaction_ss(string args1, string args2);
    public delegate IHttpActionResult apiaction_sl(string args1, long args2);
    public delegate IHttpActionResult apiaction_sss(string args1, string args2, string args3);
public delegate IHttpActionResult apiaction_o<treq>(treq data) where treq : class,new();

注:目前delegate只支持三个参数以内的接口(且参数类型目前仅支持int,long,string),如果参数不符合条件可传递对象。

以上为具体实现至于有不了解的可以在文章顶部下载代码也可以,点击公共中qq与我联系。

2.下面我来写一下它的使用:

2.1.初始化:

在global中添加如下代码:

2.2.在mvc中调用:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏dotnet core相关

WCF入门(10)

公司是做乙方的,工资还凑合,主要是项目基本都已完成,进去就是干维护,体会不到那种从头彻尾的成就感。项目中具体用了EF+Ado.net+WCF+WPF+(VB.n...

452
来自专栏JavaWeb

Mybatis源码-XXXmapper.xml中的resultMap标签解析过程

1093
来自专栏刘望舒

手动实现Android热修复

周一发布了新版本,当天晚上用户就为app未测试到的bug发飙了,恩,很快就找到了问题所在,一个容易疏忽的空指针。虽然只是一个小小的bug但是不修复是很影响用户体...

1565
来自专栏java架构师

【WP之一】]独立存储

介绍: 提供一个磁盘存储空间,他是一种虚拟的文件系统,能存储小量的数据;在默认的情况下,它只能存储1MB的文件。根据使用方式及功能的不同,独立存储空间又包含两部...

3016
来自专栏一“技”之长

Java开发GUI之可编辑区域 原

    Java的awt包中提供了单行的文本编辑组件TextField与多行的文本编辑区TextArea,这两个组件都是继承自TextComponent类。

552
来自专栏liulun

ASP.NET Core教程【三】实体字段属性、链接标签、并发数据异常、文件上传及读取

前文索引: ASP.NET Core教程【二】从保存数据看Razor Page的特有属性与服务端验证 ASP.NET Core教程【一】关于Razor Page...

2246
来自专栏c#开发者

BizTalk Orchestration execute Flat file disassembler ReceivePipeline

需求是这样,在一个inbound XML中有个一点节点使用平文件的方式存放,还要解析比如固定长度或根据特殊字符截取字段 也就是需要在流程里面先把输入的XML的节...

34813
来自专栏技术小讲堂

ASP.NET AJAX(4)__客户端访问WebService服务器端释放WebService方法客户端访问WebService客户端访问PageMethod错误处理复杂数据类型使用基础客户端代理的

服务器端释放WebService方法 编写一个普通的WebService 为WebService类添加自定义的属性标记__ScriptServiceAttrib...

2607
来自专栏跟着阿笨一起玩NET

C#实现文件数据库

本文转载:http://www.cnblogs.com/gaochundong/archive/2013/04/24/csharp_file_database....

381
来自专栏大内老A

ASP.NET Web API路由系统:Web Host下的URL路由

ASP.NET Web API提供了一个独立于执行环境的抽象化的HTTP请求处理管道,而ASP.NET Web API自身的路由系统也不依赖于ASP.NET路由...

2109

扫描关注云+社区