在我们的业务中不可避免要与第三方的系统进行交互,调用他们提供的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. 康哲20191114-1 每周例行报告kz404

    此作业的要求参见https://edu.cnblogs.com/campus/nenu/2019fall/homework/10004 本周PSP  本周进度条  本周折线图  饼状图

  2. 简单实用的PCM音频播放器--沉寂几年之后回归的第一份笔记

    ---恢复内容开始--- PCM音频网络流播放,至于用处,就不多解释了. 一个简单的类,基于NAudio,一个简单的拼装类,实例化时三个参数,依次是采样率,系统播放设备Index,播放声道,调用Pla ...

  3. html5中 input的pattern属性 和 details/summary元素

    html5--3.21 课程小结与其他新增元素 一.总结 一句话总结: input的pattern属性可以设置正则验证,比如检测学号的位数和数字区间 details/summary元素配合起来可以做元 ...

  4. pt-table-checksum解读【转】

    pt-table-checksum是目前可以说是最好的查看主从一致性的工具 先来个使用例子,有助快速上手使用 在主库执行: mysql>GRANT SELECT, PROCESS, SUPER, ...

  5. Apache-dbutils 简介及事务处理

    一:commons-dbutils简介 commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化 ...

  6. 官方Android Camera2 录像示例--停止录像时崩溃修正

    官方Android 使用Camera2示例项目地址:https://github.com/android/camera-samples 视频录像示例:https://github.com/androi ...

  7. 002 centos7中遇到的问题

    在关机的时候,发现输入密码之后竟然报错了,然后确认普通用户的密码没有问题.下面是处理方式. 一:问题 1.问题 当在终端执行sudo命令时,系统提示“caojun is not in the sudo ...

  8. Spring AOP(通知、连接点、切点、切面)

    一.AOP术语 通知(Advice)  切面的工作被称为通知.通知定义了切面是什么以及何时使用.除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题.5种通知类型: 前置通知(Before): ...

  9. 方法不会等待Task执行完才返回数据

  10. openresty开发系列11--openresty的api入门

    openresty开发系列11--openresty的api入门 1)ngx_lua模块的hello world编辑nginx下conf配置文件nginx.conf# vi nginx.conf在se ...