利用委托与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);
            }
        }
View Code

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));
        }
View Code

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定义");
        }
    }
View Code

 

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();
View Code

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

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

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

2.1.初始化:

在global中添加如下代码:

2.2.在mvc中调用:

posted @ 2016-06-29 13:02  王延领  阅读(1124)  评论(7编辑  收藏  举报