在我们的业务中不可避免要与第三方的系统进行交互,调用他们提供的API来获取相应的数据,那么对于这样的情况该怎样进行处理呢?下面就结合自己对接跨越速运接口来获取一个发运单完整的物流信息为例来说明如何在Asp.Net Core中通过代码实现。当然在他们的官方网站上面会给出具体的API调用方式以及参数格式,作为调用方只需要根据相应规则来进行编码即可,下面以我们查询某一个具体的发运单的物流信息为例来进行说明。

  下面以一个查询路由详细信息为例来进行说明。当前接口主要包括:1 概述。 2 系统参数。 3  业务参数。 4 业务参数。5 返回结果。6 响应数据格式。7 调用示例(Java语言)。这里主要是来说明如何使用C#语言来进行调用,其它语言的思路其实也是一样的。

  一 构造HttpClient对象

  这里建议使用IHttpClientFactory这个接口来创建httpClient而不是直接new一个对象,至于具体原因网上有很多原因,具体理由也是IHttpClientFactory创建的HttpClient对象能够在使用完得到更好的释放资源的效果。在Asp.Net Core中直接在构造函数中注入IHttpClientFactory接口,然后采用CreateClient方法来创建对象。  

 public LogisticsService(IHttpClientFactory httpClientFactory) {
_httpClient = httpClientFactory.CreateClient(PartsConsts.DcsPartClientName);
}

  这个CreateClient方法中需要传一个标识你现在使用的HttpClient的名称。

  二 获取参数Token

  按照他们的API规范中说的,在Headers中需要进行Token传递的,这个称之为请求票据,没有这个是无法进行验证的,首先我们需要定义一个用于请求Token的数据结构,同时还需要根据他们的规范来定义一个接收Token的数据结构。

  A   请求Token的数据结构  

public class LogisticsUser {
public string appkey { get; set; } public string appsecret { get; set; }
}

  B 接收Token的数据结构

public class CodeMsg {
public int Code { get; set; }
public string Msg { get; set; }
public bool Success { get; set; }
} public class TokenResult : CodeMsg {
public TokenData Data { get; set; }
} public class TokenData {
public string Refresh_token { get; set; } public int Expire_time { get; set; } public string Token { get; set; }
}

  C 同步请求方法

 /// <summary>
/// 同步请求post(键值对形式)
/// </summary>
/// <param name="url"></param>
/// <param name="postdate"></param>
/// <param name="formData"></param>
/// <param name="charset"></param>
/// <param name="mediaType"></param>
/// <returns></returns>
public async Task<string> HttpPostAsync(string url, string postdate = null, List<KeyValuePair<string, string>> formData = null,
string charset = "UTF-8", string mediaType = "application/json") { HttpContent content = new StringContent(postdate);
content.Headers.ContentType = new MediaTypeHeaderValue(mediaType) {
CharSet = charset
};
foreach (var data in formData) {
content.Headers.Add(data.Key, data.Value);
}
var response = await _httpClient.PostAsync(url, content); var result = await response.Content.ReadAsStringAsync(); return result;
}

  这个方法是一个常规的异步请求方法,这里使用HttpContent作为数据载体,将一些重要的系统参数添加到Headers里面,将业务参数传递到StringContent的构造函数中去,最后调用PostAsync异步方法发送Post请求,请求完了通过返回的Response来获取返回的数据,通过这种方式来获取完整的数据结构。这里特别需要注意如果第一次请求Token失败则可以再次请求重新刷新Token,最后将获取的Json类型Token反序列化为我们定义的TokenResult结构,这样我们就能够正常获取到Token数据了。

  三 获取发运单数据

  我们之前所有的工作都是为了能够获取到最终的业务数据,那么这里我们也是一样,首先要定义请求和接收数据的数据结构,首先是请求的数据结构。

 public class LogisticsInputModel {
[JsonProperty("customerCode")]
public string CustomerCode { get; set; } [JsonProperty("waybillNumbers")]
public string[] WaybillNumbers { get; set; }
}

  这里面CustomerCode是我们用户编码,这个是唯一的,这是跨越速运官方给予的用户凭证,第二个WaybillNumbers 就是我们需要查询的发运单的集合,这里的接口支持一次性查询多个发运单数据,所以接口使用string[ ]数组类型。

  下面来说一下根据官方定义来定义查询物流信息的接口定义。

    /// <summary>
/// 跨越速运查询物流信息接口
/// </summary>
public class LogisticInfoModel {
public string Code { get; set; } public string Msg { get; set; } public bool? Success { get; set; } public DataInfo Data { get; set; } public string TraceId { get; set; }
} public class DataInfo {
public string ResultCount { get; set; } public IList<EsWayBillInfo> EsWayBill { get; set; }
} public class EsWayBillInfo {
public EsWayBillInfo() {
ExteriorRouteList = new List<ExteriorRoute>();
} public string WaybillNumber { get; set; } public string ProductCode { get; set; } public string ReceiveDate { get; set; } public string Receiver { get; set; } public string ExpectedDate { get; set; } public string MailingTime { get; set; } public string ServiceMode { get; set; } public string MailingAddress { get; set; } public string ReceivingAddress { get; set; } public string Addressee { get; set; } public string Sender { get; set; } public string TotalFreightAmount { get; set; } public string Count { get; set; } public string FreightWeight { get; set; } public decimal? Size { get; set; } public IList<ExteriorRoute> ExteriorRouteList { get; set; }
} public class ExteriorRoute {
public int Id { get; set; } public string RouteStep { get; set; } public string RouteDescription { get; set; } public string UploadDate { get; set; }
}

  有了输入请求参数,当然也需要能够接受最终数据的数据接口,这些数据结构首先都要定义好,而且必须和官方保持一致,否则就无法进行反序列化操作。

  有了这些准备工作我们来看看最核心的获取业务数据的过程,我们会在稍后来对其中的一些代码进行说明。

public async Task<IList<EsWayBillInfo>> GetLogisticsInformationAsync(LogisticsInputModel input) {
var parameter = new List<KeyValuePair<string, string>>();
var nowDate = (DateTime.Now.ToUniversalTime() - new DateTime(, , )).TotalMilliseconds.ToString(CultureInfo.InvariantCulture);
var jsonParam = JsonConvert.SerializeObject(input);
var logisticsUser = new LogisticsUser() {
appkey = Appkey,
appsecret = Appsecret
};
parameter.Add(new KeyValuePair<string, string>("X-from", "openapi_ap")); var tokenResult = await HttpPostAsync(TokenUrl, JsonConvert.SerializeObject(logisticsUser), parameter);
var codeMsg = JsonConvert.DeserializeObject<TokenResult>(tokenResult); //Token失效,调用刷新Token接口,返回新Token
if (codeMsg.Data.Expire_time <= ) {
var tokenRefreshResult = await HttpPostAsync(RefreshTokenUrl,
"{\"refresh_token\": \"" + codeMsg.Data.Refresh_token + "\"}", parameter);
codeMsg = JsonConvert.DeserializeObject<TokenResult>(tokenRefreshResult);
} parameter.Clear();
parameter.Add(new KeyValuePair<string, string>("appkey", Appkey));
parameter.Add(new KeyValuePair<string, string>("format", Format));
parameter.Add(new KeyValuePair<string, string>("timestamp", nowDate));
parameter.Add(new KeyValuePair<string, string>("method", QueryRoute));
parameter.Add(new KeyValuePair<string, string>("sign", MD5Hash(Sign + nowDate + jsonParam).ToUpper()));
parameter.Add(new KeyValuePair<string, string>("token", codeMsg.Data.Token));
var result = await HttpPostAsync(RestUrl, jsonParam, parameter);
return JsonConvert.DeserializeObject<LogisticInfoModel>(result)?.Data?.EsWayBill;
}

  这里有一些需要说明的部分,首先获取nowDate的时候是获取UTC时间,其次获取sign的时候需要对内容进行MD5加密的过程。Asp.Net Core中的MD5加密比较简单,采用下面的方式即可。

/// <summary>
/// netcore下的实现MD5加密
/// </summary>
/// <param name="input">加密内容</param>
/// <returns></returns>
private string MD5Hash(string input) {
using (var md5 = MD5.Create()) {
var result = md5.ComputeHash(Encoding.ASCII.GetBytes(input));
var strResult = BitConverter.ToString(result);
return strResult.Replace("-", "");
}
}

  这里使用Using包裹便于进行非托管对象的释放,这里需要注意,还有一些常用的const变量定义为局部变量即可,有了这些就能够创建一个完整的根据发运单号来获取完整的物流数据的第三方API对接过程了。

private const string Appkey = "";
private const string Format = "json";
private const string Appsecret = "XXXE034XXX355889DC68BB40BEDXXX0";
private const string QueryRoute = "open.api.openCommon.queryRoute";
private const string Sign = "XXXE034545E355889DC68BB40BEDXXX";
private const string TokenUrl = "https://open.ky-express.com/security/token";
private const string RefreshTokenUrl = "https://open.ky-express.com/security/token/refresh";
private const string RestUrl = "https://open.ky-express.com/router/rest";

  最后我们来看看通过整个调用过程获取物流信息并在系统中进行展示的效果。

  图一 获取发运单对应物流信息

  

Asp.Net Core 调用第三方Open API查询物流数据的更多相关文章

  1. 从头编写 asp.net core 2.0 web api 基础框架 (1)

    工具: 1.Visual Studio 2017 V15.3.5+ 2.Postman (Chrome的App) 3.Chrome (最好是) 关于.net core或者.net core 2.0的相 ...

  2. 【转载】从头编写 asp.net core 2.0 web api 基础框架 (1)

    工具: 1.Visual Studio 2017 V15.3.5+ 2.Postman (Chrome的App) 3.Chrome (最好是) 关于.net core或者.net core 2.0的相 ...

  3. 从头编写 asp.net core 2.0 web api 基础框架 (3)

    第一部分:http://www.cnblogs.com/cgzl/p/7637250.html 第二部分:http://www.cnblogs.com/cgzl/p/7640077.html 之前我介 ...

  4. 【转载】从头编写 asp.net core 2.0 web api 基础框架 (3)

    Github源码地址:https://github.com/solenovex/Building-asp.net-core-2-web-api-starter-template-from-scratc ...

  5. 使用 ASP.NET Core MVC 创建 Web API(五)

    使用 ASP.NET Core MVC 创建 Web API 使用 ASP.NET Core MVC 创建 Web API(一) 使用 ASP.NET Core MVC 创建 Web API(二) 使 ...

  6. 使用 ASP.NET Core MVC 创建 Web API(三)

    使用 ASP.NET Core MVC 创建 Web API 使用 ASP.NET Core MVC 创建 Web API(一) 使用 ASP.NET Core MVC 创建 Web API(二) 十 ...

  7. 从零开始学习 asp.net core 2.1 web api 后端api基础框架(二)-创建项目

    原文:从零开始学习 asp.net core 2.1 web api 后端api基础框架(二)-创建项目 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.ne ...

  8. 【ASP.NET Core学习】Web API

    这里介绍在ASP.NET Core中使用Web API创建 RESTful 服务,本文使用VSCode + NET Core3.0 创建简单Rest API 格式化输出 JSON Patch请求 Op ...

  9. 使用 ASP.NET Core MVC 创建 Web API(一)

    从今天开始来学习如何在 ASP.NET Core 中构建 Web API 以及每项功能的最佳适用场景.关于此次示例的数据库创建请参考<学习ASP.NET Core Razor 编程系列一> ...

随机推荐

  1. [转] Hadoop入门系列(一)Window环境下搭建hadoop和hdfs的基本操作

    转自:https://blog.csdn.net/qq_32938169/article/details/80209083 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载 ...

  2. 本地spark下保存rdd为文件

    写随笔大概也是做笔记记录下自己思考的意思吧,之前有些事情觉得做随笔还是比较有用的,mark一下一个有用的网址 关于rdd的操作,网上有很多很多的教程,当初全部顺一遍,除了对rdd这个类型有了点概念,剩 ...

  3. fluent中interpolate的用法

    原视频下载地址: https://pan.baidu.com/s/1hTD6tIlYL1S0nm30riAD9w 密码: ngv9

  4. GO语言Error处理

    Go语言没有提供像Java.C#.Python语言中的try...catch异常处理方式,而是通过函数返回值逐层往上抛.好处就是避免漏掉本应处理的错误.坏处是代码啰嗦. 错误与异常区别 错误指的是可能 ...

  5. pymongo错误记录

    1.AutoReconnect pymongo.errors.AutoReconnect: connection closed 2.ServerSelectionTimeoutError pymong ...

  6. 【软工实践】团队项目Snug-选题报告

    组长博客链接 组长博客 NABCD分析引用 NEED 需求 根据我们的调查显示,大部分人都有着不规律的生活习惯,他们都希望有一款软件能够帮助他们,养成一个适合自己的较规律的生活习惯.我们的Snug正是 ...

  7. 微信小程序的z-index在苹果ios无效

    1.在微信开发者工具可以正常显示 2.在安卓真机手机可以正常显示 3.在ios手机真机无法正常显示 原因:父级view的css属性有 position: fixed; ,把它注释掉即可

  8. java/spring boot/dubbo/spring cloud/微服务/SOA/分布式经典电子书籍pdf下载

    微服务系列 官方文档是最好的资料了. spring cloud官方文档:https://cloud.spring.io/spring-cloud-static/Greenwich.RELEASE/si ...

  9. SpringBoot整合Quartz和H2的例子

    话不多说,直接上代码: pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xml ...

  10. Flutter -------- Drawer侧滑

    侧滑菜单在安卓App里面非常常见 抽屉通常与Scaffold.drawer属性一起使用.抽屉的子项通常是ListView,其第一个子项是DrawerHeader ,它显示有关当前用户的状态信息.其余的 ...