使用WebApiClient请求和管理Restful Api

前言

本篇文章的内容是WebApiClient应用说明篇,如果你没有了解过WebApiClient,可以先阅读以下相关文章:

背景

随着Wcf、Webservice等的SOAP的份额越来越少,以及Restful Api的兴起,目前几乎所有新平台提供的接口,都只提供Restful Api,而.net平台下,没有类似Wcf这么简单的客户端可以直接请求和管理这些Restful api的解决方案,.net平台提供的HttpWebRequest、WebClient和HttpClient这三个类库,可用于实现Http接口的请求,但相比wcf得益于soap自我描述实现的自动生成客户端调用代码,Restful就没这么方便了,无论使用HttpWebRequest还是HttpClient,都需要对每个Api缩写沉长的调用代码。

使用WebApiClient

WebApiClient是在这样的背景下产生一款Http全异步的客户端库,它的出现,大幅度减轻了接口调用者的工作量,而且在调用Http接口上还非常容易维护和更新,还可以轻松应对设计不太友好的一些http接口。

使用WebApiClient,编程人员不再需要手动实现路径拼接、参数拼接、请求体组装和响应映射为模型这些繁琐的过程,以下为WebApiClient应用到项目中的一般流程:

1 声明http接口的Interface

[JsonReturn]
public interface IIotRemotePush : IDisposable
{
    /// <summary>
    /// 创建远程推送账号
    /// </summary>
    /// <param name="auth">授权</param>
    /// <returns></returns>
    [HttpPost("/v1/RemotePush/CreateAccount")]
    ITask<ApiResult<PushAccount>> CreateAccountAsync(IotBasicAuth auth);

    /// <summary>
    /// 获取推送服务信息
    /// </summary>
    /// <param name="id">pushId</param>
    /// <returns></returns>
    [HttpGet("/v1/Mqtt/GetPushSevice?id={id}")]
    ITask<ApiResult<MqttService>> GetPushSeviceAsync(string id);
}

/// <summary>
/// Api结果接口
/// </summary>
public interface IApiResult
{
    /// <summary>
    /// 错误码
    /// </summary>      
    ErrorCode Code { get; set; }

    /// <summary>
    /// 相关提示信息
    /// </summary>
    string Msg { get; set; }
}


/// <summary>
/// 表示Api结果
/// </summary>
public class ApiResult<T> : IApiResult
{
    /// <summary>
    /// 错误码
    /// </summary>
    public ErrorCode Code { get; set; }

    /// <summary>
    /// 相关提示信息
    /// </summary>
    public string Msg { get; set; }

    /// <summary>
    /// 业务数据
    /// </summary>
    public T Data { get; set; }
}

2 调用http接口

WebApiClient不需要开者实现接口,使用HttpApiClient.Create方法可以动态创建接口的实现类的实例,调用实例的方法,就完成一个Api的请求。

using (var iotApi = HttpApiClient.Create<IIotRemotePush>())
{
    var auth = new IotBasicAuth(config.AppId, config.AppToken);
    var createResult = await iotApi.CreateAccountAsync(auth);
    if (createResult.Code != ErrorCode.NoError)
    {
        return null;
    }

    config.PushId = createResult.Data.Id;
    config.PushToken = createResult.Data.Token;
    await db.SaveChangesAsync();

    return config;
}

3 异常定义与异常处理

在以上接口中,接口返回的都是ApiResult类型,此类型定义了一个ErrorCode类型的Code字段,这是业务的错误码,我们可以把它转换为.net的异常来处理。

/// <summary>
/// 表示Iot异常
/// </summary>
public class IotException : Exception
{
    /// <summary>
    /// 错误码
    /// </summary>
    public ErrorCode ErrorCode { get; private set; }

    /// <summary>
    /// Iot异常
    /// </summary>
    /// <param name="apiResult">api结果值</param>
    public IotException(IApiResult apiResult)
        : base(apiResult.Msg)
    {
        this.ErrorCode = apiResult.Code;
    }
}

我们还应该在Interface上扩展JsonResult,用于将ApiResult的ErrorCode转换为IotException,并抛出:

/// <summary>
/// 表示IotJson结果
/// </summary>
public class IotJsonResultAttribute : JsonReturnAttribute
{
    protected override async Task<object> GetTaskResult(ApiActionContext context)
    {
        var apiResult = await base.GetTaskResult(context) as IApiResult;
        if (apiResult != null && apiResult.Code != ErrorCode.NoError)
        {
            throw new IotException(apiResult);
        }
        return apiResult;
    }
}

然后将新的IotJsonResultAttribute在Interface上替换JsonReturnAttribute:

[IotJsonResult]
public interface IIotRemotePush : IDisposable
{
   ...
}

最后,调用http接口的时候,可以使用Handle()扩展方法处理异常:

using (var iotApi = HttpApiClient.Create<IIotRemotePush>())
{
    var auth = new IotBasicAuth(config.AppId, config.AppToken);
    var createResult = await iotApi.CreateAccountAsync(auth)
        .Handle()
        .WhenCatch<IotException>(ex =>
        {
            // process exception
            return default(ApiResult<PushAccount>);
        })
        .WhenCatch<Exception>(ex =>
        {
            // process exception
            return default(ApiResult<PushAccount>);
        });

    if (createResult == null)
    {
        return null;
    }

    config.PushId = createResult.Data.Id;
    config.PushToken = createResult.Data.Token;
    await db.SaveChangesAsync();

    return config;
}

WebApiClient现状

WebApiClient项目目前已加入.NET China Foundation,正在为.net开源作出自己的一点贡献。

posted @ 2018-03-08 17:27  jiulang  阅读(4842)  评论(1编辑  收藏  举报