在较早期的随笔《ABP开发框架先后端开发系列---(5)Web API调用类在Winform项目中的使用》已经介绍了Web API调用类的封装处理,虽然这些调用类咱们可使用代码生成工具快速生成,不过自定义接口,仍是须要咱们对这些接口进行实现,以便发起对Web API的调用,并得到相应的数据返回。本篇随笔介绍使用API调用类的封装类,进行函数的抽象,根据方法名称的推断,构建URL或者WebClient的请求类型,从而实现全部API调用函数的简化处理。html
ABP框架的架构图示,以下图所示(以字典模块为例说明)后端
针对Web API接口调用的封装,为了适应客户端快速调用的目的,这个封装做为一个独立的封装层,以方便各个模块之间进行共同调用。api
而ABP的Web API调用类则须要对Web API接口调用进行封装,以下所示。架构
如对于字典模块的API封装类,它们继承一个相同的基类,而后实现特殊的自定义接口便可,这样能够减小常规的Create、Get、GetAll、Update、Delete等操做的代码,这些所有由调用基类进行处理,而只须要实现自定义的接口调用便可。app
咱们对于常规的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控制器的方法是一一对应的,所以方法名称能够经过对当前接口名称的推断进行得到,以下所示。async
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); 这样方式post
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类的代码以下所示。
这样咱们再多的接口,都一行代码调用解决问题,很是简单,今后客户端封装类的实现就很是简单了,只须要注意有没有返回值便可,其余的都没有什么不一样。
只须要注意的是,咱们定义接口的时候,尽量使用复杂类型对象,这样就能够根据对象属性名称和值进行构建URL或者JSON的了。