QuickWebApi:使用Lambada方式,完成對WebApi的開發和調用。

QuickWebApi

目的:使用Lambada方式,完成對WebApi的開發和調用。java


原因:爲了解耦服務和展示,將愈來愈多的使用WebApi提供各類服務;隨着服務的細化,WebApi的接口將愈來愈多,成百上千。如何方便的管理和調用規模龐大的WebApi接口成了開發者頭疼的問題。

設計:經過自定義的QuickWebApiAttribute來對業務接口進行規範和說明,並生成配置文件;能夠經過修改配置文件,達成對WebApi的地址的調整而不用修改代碼。

效果:除了從新搭建的系統可使用外,對於一些其它語言(如java等)提供的webapi,只須要定義出相應的業務接口,即可以使用git

原理:經過HttpClient類,使用Json做爲請求和響應的數據格式實現。並經過定義相應的delegate,完成Lambada方式的調用,目前delegate只支持三個參數之內的接口(且參數類型目前僅支持int,long,string),若是超過三個參數或者其餘的複雜類型,則應經過自定義對象的方式完成。github

    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的Lambada化和參數的傳遞解析實現:web

        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定義");
        }

 若是參數不是對象(須要注意的是,雖然處理了對DataTime類型的處理,但原則上不該出現該類型參數),則:ajax

        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定義");
        }

 以上是WebApi訪問Lambada化的核心代碼塊。如需瞭解更多,在文章結尾有個人源碼地址鏈接。json

接下來介紹一下QuickWebApi在實際開發過程當中的使用,包括接口服務端和接口調用端的樣例代碼。

服務業務接口及模型設計:api

    //數據模型
    public class customer
    {
        public int id { get; set; }
        public long timestamp { get; set; }
        public string name { get; set; }
        public int age { get; set; }
        public DateTime birthday { get; set; }
        public bool state { get; set; }
    }
    //業務接口動態庫聲明
    [assembly: QuickWebApiDll("customer", "http://localhost:11520")]
    //業務接口聲明,接口中的返回值爲IHttpActionResult,以便更好的處理HTTP響應
    [QuickWebApi("customer", "api/customer_service", "用戶管理")]
    public interface icustomer
    {
        [QuickWebApi(MethodType.HTTPGET, "用戶列表", "列舉用戶信息")]
        IHttpActionResult list();
        [QuickWebApi(MethodType.HTTPGET)]
        IHttpActionResult info(int customerid);
        [QuickWebApi(MethodType.HTTPPOST)]
        IHttpActionResult update(int id, string name);
        [QuickWebApi(MethodType.HTTPDEL)]
        IHttpActionResult del(int id);
        [QuickWebApi(MethodType.HTTPPUT)]
        IHttpActionResult save(customer customer);
    }
    //業務接口實現,設置路由機制
    [Route("api/customer_service/{action}/")]
    public class customerController : ApiController, icustomer
    {
        [HttpGet]
        public IHttpActionResult list()
        {
            return Ok(new result(0, null, DB.customers.ToList().Count, DB.customers.ToList()));
        }

        [HttpGet]
        public IHttpActionResult info(int customerid)
        {
            return Ok(new result(DB.customers.SingleOrDefault(c => c.id == customerid)));
        }

        [HttpPost]
        public IHttpActionResult update(int id, string name)
        {
            var cust = DB.customers.SingleOrDefault(c => c.id == id);
            cust.name = name;
            return Ok(new result());
        }

        [HttpDelete]
        public IHttpActionResult del(int id)
        {
            DB.customers.RemoveAll(c => c.id == id);
            return Ok(new result());
        }

        [HttpPut]
        public IHttpActionResult save(customer customer)
        {
            DB.customers.RemoveAll(c => c.id == customer.id);
            DB.customers.Add(customer);
            return Ok(new result());
        }
    }
    

 

調用端相應的配置和加載:服務器

    //在服務啓動時調用,通常在global中
    webapifactory.Instance.Build_Apis();
    webapifactory.Instance.Load_Apis();

    //配置文件格式(*.xml)以下(每一個業務接口生成一個獨立的配置文件,便於維護):
    <?xml version="1.0" encoding="utf-16"?>
    <ArrayOfWebApiNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <WebApiNode>
        <Name>用戶管理</Name>
        <Title>QuickWebApi.Sample.Apis</Title>
        <Version>1.0.0.0</Version>
        <Service>customer</Service>
        <Route>api/customer_service</Route>
        <Uri>http://localhost:11520</Uri>
        <Actions>
          <WebApiMethod>
            <Method>HTTPGET</Method>
            <Action>list</Action>
            <Name>用戶列表</Name>
            <Comment>列舉用戶信息</Comment>
          </WebApiMethod>
          <WebApiMethod>
            <Method>HTTPGET</Method>
            <Action>info</Action>
          </WebApiMethod>
          <WebApiMethod>
            <Method>HTTPPOST</Method>
            <Action>update</Action>
          </WebApiMethod>
          <WebApiMethod>
            <Method>HTTPDEL</Method>
            <Action>del</Action>
          </WebApiMethod>
          <WebApiMethod>
            <Method>HTTPPUT</Method>
            <Action>save</Action>
          </WebApiMethod>
        </Actions>
      </WebApiNode>
    </ArrayOfWebApiNode>

    //並同時生產簡單的業務接口描述文件(*.txt):
    001,用戶管理:QuickWebApi.Sample.Apis-1.0.0.0-
    001,http://localhost:11520/api/customer_service/list,用戶列表,列舉用戶信息
    002,http://localhost:11520/api/customer_service/info,,
    005,http://localhost:11520/api/customer_service/update,,
    006,http://localhost:11520/api/customer_service/del,,
    008,http://localhost:11520/api/customer_service/save,,

 


   調用端使用方式數據結構

    public class HomeController : Controller
    {
        public object customers()
        {
            var ret = new webapi<icustomer>().invoke(i => i.list);
            return ret;
        }
        public JsonResult customer_list()
        {
            var ret = new webapi<icustomer, List<customer>>().invoke(i => i.list);
            List<object> custs = new List<object>();
            foreach (var cust in ret.data)
            {
                custs.Add(new { id = cust.id, name = cust.name, age = cust.age });
            }
            return Json(custs, JsonRequestBehavior.AllowGet);
        }
        public object info()
        {
            var ret = new webapi<icustomer>().invoke(i => i.info, 4);
            return ret;
        }
        public object update()
        {
            var ret = new webapi<icustomer>().invoke(i => i.update, 3, "new name");
            return ret;
        }
        public object save()
        {
            var cust = new customer() { id = 3, name = "new name", age = 22, timestamp = DateTime.Now.Ticks, birthday = DateTime.Now.AddYears(-10) };
            var ret = new webapi<icustomer>().invoke(i => i.save, cust);
            return ret;
        }
        public object delete()
        {
            var ret = new webapi<icustomer>().invoke(i => i.del, 4);
            return ret;
        }
    }

 


其它說明及注意事項:ui

    //invoke方法的返回結果的數據結構以下:
    public class result<T> where T : class, new()
    {
        //若是通信不正常,則爲返回的HTTP狀態嗎;不然爲服務端返回的狀態嗎,默認值爲0(正常)
        public int errcode { get; set; }    
        //服務端返回的信息
        public string errmsg { get; set; }
        //服務端返回的複雜數據結構,經過Json進行傳輸
        public T data { get; set; }
        //若是須要返回整型
        public long id { get; set; }
        //服務器端時間
        public DateTime time { get; set; }
     }
     //若是頁面上經過ajax直接調用WebApi接口,則須要在服務端註冊JsonFormatter,則ajax能夠直接獲得result的json格式:
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            webapifactory.Instance.Register_JsonFormatter(config);

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

        }

 


 

感謝您的閱讀。源碼目前QuickWebApi還有一些其它想法和設計會未加入其中,後續會繼續修繕。且還存在一些未解決的問題,歡迎您能貢獻您的智慧和意見。

相關文章
相關標籤/搜索