ABP开发框架前后端开发系列---(10)Web API调用类的简化处理

在较早期的随笔《ABP开发框架前后端开发系列---(5)Web API调用类在Winform项目中的使用》已经介绍了Web API调用类的封装处理,虽然这些调用类我们可以使用代码生成工具快速生成,不过自定义接口,还是需要我们对这些接口进行实现,以便发起对Web API的调用,并获得相应的数据返回。本篇随笔介绍使用API调用类的封装类,进行函数的抽象,根据方法名称的推断,构建URL或者WebClient的请求类型,从而实现所有API调用函数的简化处理。

1、ABP框架服务端和客户端的处理

ABP框架的架构图示,如下图所示(以字典模块为例说明)

image

针对Web API接口调用的封装,为了适应客户端快速调用的目的,这个封装作为一个独立的封装层,以方便各个模块之间进行共同调用。

image

而ABP的Web API调用类则需要对Web API接口调用进行封装,如下所示。

image

如对于字典模块的API封装类,它们继承一个相同的基类,然后实现特殊的自定义接口即可,这样可以减少常规的Create、Get、GetAll、Update、Delete等操作的代码,这些全部由调用基类进行处理,而只需要实现自定义的接口调用即可。

2、Web API调用类的简化处理

我们对于常规的Web API调用接口处理,如下代码所示。

public async virtual Task<AuthenticateResult> Authenticate(string username, string password)
{
    var url = string.Format("{0}/api/TokenAuth/Authenticate", ServerRootAddress);
    var input = new
    {
        UsernameOrEmailAddress = username,
        Password = password
    };

    var result = await apiClient.PostAsync<AuthenticateResult>(url, input);
    return result;
}

这种方法的处理,就需要自己拼接URL地址,以及传递相关的参数,一般情况下,我们的Web API Caller层类的函数和Web API控制器的方法是一一对应的,因此方法名称可以通过对当前接口名称的推断进行获得,如下所示。

public async Task<bool> ChangePassword(ChangePasswordDto input)
{
    AddRequestHeaders();//加入认证的token头信息
    string url = GetActionUrl(MethodBase.GetCurrentMethod());//获取访问API的地址(未包含参数)

    return await apiClient.PostAsync<bool>(url, input);
}

函数AddRequestHeaders 通过在调用前增加对应的AccessToken信息,然后URL通过当前方法的推断即可构建一个完整的URL,但是这个也仅仅是针对POST的方法,因为ABP框架根据方法的名称前缀的不同,而采用POST、GET、Delete、PUT等不同的HTTP处理操作。

如GET方法,则是需要使用GET请求

public async Task<List<RoleDto>> GetRolesByUser(EntityDto<long> input)
{
    AddRequestHeaders();//加入认证的token头信息
    string url = GetActionUrl(MethodBase.GetCurrentMethod());//获取访问API的地址(未包含参数)
    url = GetUrlParam(input, url);

    var result = await apiClient.GetAsync<List<RoleDto>>(url);
    return result;
}

而对于删除方法,则使用下面的DELETE请求,DELETE 和PUT操作,需要把参数串联成GET的URL形式,类似 url += string.Format("?Id={0}", id); 这样方式

        public virtual async Task Delete(TDeleteInput input)
        {
            AddRequestHeaders();//加入认证的token头信息
            string url = GetActionUrl(MethodBase.GetCurrentMethod());//获取访问API的地址(未包含参数)
            url += GetUrlParam(input, url);
            var result = await apiClient.DeleteAsync(url);
            return result;
        }

对于更新的操作,使用了PUT方法

        public async virtual Task<TEntityDto> Update(TUpdateInput input)
        {
            AddRequestHeaders();//加入认证的token头信息
            string url = GetActionUrl(MethodBase.GetCurrentMethod());//获取访问API的地址(未包含参数)
            var result = await apiClient.PutAsync<TEntityDto>(url, input, null);
            return result;
        }

上面这些方法,我们根据规律,其实可以进一步进行简化,因为这些操作大多数类似的。

首先我们看到变化的地方,就是根据方法的前缀采用GET、POST、DELETE、PUT方法,还有就是URL串联字符串的不同,对于GET、Delete方法,参数使用的是组成URL方式,参数使用的是JSON提交内容方式。

根据这些变化,我们在基类提炼一个统一的处理方法DoActionAsync 来处理这些不同的操作。

        /// <summary>
        /// 根据方法名称自动执行GET/POST/PUT/DELETE请求方法
        /// </summary>
        /// <param name="method"></param>
        /// <param name="input"></param>
        protected virtual async Task DoActionAsync(MethodBase method, object input = null)
        {
            await DoActionAsync<object>(method, input);
        }
        /// <summary>
        /// 根据方法名称自动执行GET/POST/PUT/DELETE请求方法
        /// </summary>
        /// <param name="method"></param>
        /// <param name="input"></param>
        protected virtual async Task<TResult> DoActionAsync<TResult>(MethodBase method, object input = null)
        {
            AddRequestHeaders();//加入认证的token头信息

            string action = GetMethodName(method);
            var url = string.Format("{0}/api/services/app/{1}/{2}", ServerRootAddress, DomainName, action);//获取访问API的地址(未包含参数)
            var httpVerb = DynamicApiVerbHelper.GetConventionalVerbForMethodName(action);
            if(httpVerb == HttpVerb.Get || httpVerb == HttpVerb.Delete)
            {
                if (input != null)
                {
                    //Get和Delete的操作,需要组装URL参数
                    url = GetUrlParam(input, url);
                }
            }

            int? timeout = null;
            return await apiClient.DoActionAsync<TResult>(url, timeout, httpVerb.ToString().ToLower(), input);
        }

这样,有了这两个函数的支持,我们可以简化很多操作代码了。

例如对于Update方法,简化的代码如下所示。

        public async virtual Task<TEntityDto> Update(TUpdateInput input)
        {
            return await DoActionAsync<TEntityDto>(MethodBase.GetCurrentMethod(), input);
        }

对于删除操作,简化的代码依旧也是一行代码

        public virtual async Task Delete(TDeleteInput input)
        {
            await DoActionAsync(MethodBase.GetCurrentMethod(), input);
        }

GET操作,也是一行代码

        public async virtual Task<TEntityDto> Get(TGetInput input)
        {
            return await DoActionAsync<TEntityDto>(MethodBase.GetCurrentMethod(), input);
        }

现在你看到,所有的客户端API封装类调用,都已经非常简化,大同小异了,主要就是交给基类函数进行推断调用处理即可。

如用户操作的APICaller类的代码如下所示。

image

这样我们再多的接口,都一行代码调用解决问题,非常简单,从此客户端封装类的实现就非常简单了,只需要注意有没有返回值即可,其他的都没有什么不同。

只需要注意的是,我们定义接口的时候,尽可能使用复杂类型对象,这样就可以根据对象属性名称和值进行构建URL或者JSON的了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容