欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#对接----韵达开发平台--取电子面单

程序员文章站 2022-04-28 09:05:43
引子 最近根据业务的一些需求,所以放弃从快递鸟对接去电子面单,转而直接对接韵达开发平台:http://open.yundasys.com/ ,中间踩了一些坑,借此做了一个小案例给大伙,瞅瞅,若有需改进之处,还请指出!!! 废话不多数:首先咱先对韵达的一些接口参数了解清楚: 当然附上地址:http:/ ......

引子

最近根据业务的一些需求,所以放弃从快递鸟对接去电子面单,转而直接对接韵达开发平台: ,中间踩了一些坑,借此做了一个小案例给大伙,瞅瞅,若有需改进之处,还请指出!!!

废话不多数:首先咱先对韵达的一些接口参数了解清楚:

当然附上地址:

还有接口的一些SDK文件地址,这个就各位观众大老爷们自己去看了:

 

解决方案

上代码走起:基础参数的模型

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
  //请求参数 class RequestVO { /// <summary> /// XML数据内容 /// </summary> public string xmldata { get; set; } /// <summary> /// 合作社区ID,由韵达给大客户提供 /// </summary> public string partnerid { get; set; } /// <summary> /// 密码 /// </summary> public string password { get; set; } /// <summary> /// 数据请求类型,如request=data;其中data表示下单,详细请见request字典表 /// </summary> public string request { get; set; } /// <summary> /// 请求的版本,当前版本为1.0 /// </summary> public string version { get; set; } } }

  

主体参数模型

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace ConsoleApplication2
{
    /// <summary>
    /// 数据体
    /// </summary>
    public class Orders
    {
        [XmlElement("order")]
        public List<Order> order { get; set; }
    }

    /// <summary>
    /// 韵达取号订单信息
    /// </summary>
    public class Order
    {
        /// <summary>
        /// 订单唯一序列号
        /// </summary>
        public string order_serial_no { get; set; }
        /// <summary>
        /// 大客户系统订单的订单号
        /// </summary>
        public string khddh { get; set; }
        /// <summary>
        /// 内部参考号,供大客户自己使用,可以是客户的客户编号
        /// </summary>
        public string nbckh { get; set; }
        /// <summary>
        /// 单号
        /// </summary>
        public string mailno { get; set; }
        /// <summary>
        /// 发件人
        /// </summary>
        [XmlElement("sender")]
        public Sender sender { get; set; }
        /// <summary>
        /// 收件人
        /// </summary>
        [XmlElement("receiver")]
        public Receiver receiver { get; set; }
        /// <summary>
        /// 物品重量
        /// </summary>
        public long weight { get; set; }
        /// <summary>
        /// 尺寸,格式(长,宽,高),单位cm
        /// </summary>
        public string size { get; set; }
        /// <summary>
        /// 货物金额
        /// </summary>
        public decimal value { get; set; }
        /// <summary>
        /// 商品集合
        /// </summary>
        [XmlElement("items")]
        public Items items { get; set; }
        /// <summary>
        /// 订单备注
        /// </summary>
        public string remark { get; set; }
        /// <summary>
        /// 可以自定义显示信息1
        /// </summary>
        public string cus_area1 { get; set; }
        /// <summary>
        /// 可以自定义显示信息2
        /// </summary>
        public string cus_area2 { get; set; }

    }
    public class Sender
    {
        /// <summary>
        /// 姓名
        /// </summary>
        public string name { get; set; }
        /// <summary>
        /// 公司
        /// </summary>
        public string company { get; set; }
        /// <summary>
        /// 严格按照国家行政区划,省市区三级,逗号分隔。示例上海市,上海市,青浦区(cod订单必填)
        /// </summary>
        public string city { get; set; }
        /// <summary>
        /// 需要将省市区划信息加上,例如:上海市,上海市,青浦区盈港东路7766号
        /// </summary>
        public string address { get; set; }
        /// <summary>
        /// 邮编
        /// </summary>
        public string postcode { get; set; }
        /// <summary>
        /// 固定电话
        /// </summary>
        public string phone { get; set; }
        /// <summary>
        /// 移动电话固定电话或移动电话至少填一项
        /// </summary>
        public string mobile { get; set; }

        public string branch { get; set; }
    }
    public class Receiver
    {
        /// <summary>
        /// 姓名
        /// </summary>
        public string name { get; set; }
        /// <summary>
        /// 公司
        /// </summary>
        public string company { get; set; }
        /// <summary>
        /// 严格按照国家行政区划,省市区三级,逗号分隔。示例上海市,上海市,青浦区(cod订单必填)
        /// </summary>
        public string city { get; set; }
        /// <summary>
        /// 需要将省市区划信息加上,例如:上海市,上海市,青浦区盈港东路7766号
        /// </summary>
        public string address { get; set; }
        /// <summary>
        /// 邮编
        /// </summary>
        public string postcode { get; set; }
        /// <summary>
        /// 固定电话
        /// </summary>
        public string phone { get; set; }
        /// <summary>
        /// 移动电话固定电话或移动电话至少填一项
        /// </summary>
        public string mobile { get; set; }
        public string branch { get; set; }
    }
    /// <summary>
    /// 明细集合
    /// </summary>
    public class Items
    {
        [XmlElement("item")]
        public List<Item> item { get; set; }
    }
    /// <summary>
    /// 明细信息
    /// </summary>
    public class Item
    {
        /// <summary>
        /// 商品名称
        /// </summary>
        public string name { get; set; }
        /// <summary>
        /// 商品数量
        /// </summary>
        public int number { get; set; }
        /// <summary>
        /// 商品备注
        /// </summary>
        public string remark { get; set; }
    }
}

  

请求方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using System.Collections.Specialized;
using System.Net;


namespace ConsoleApplication1
{
    /// <summary>
    /// POST提交
    /// </summary>
    class HttpClient
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="url"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static HttpWebResponse post(String url, IDictionary<string, string> parameters)
        {
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

            //如果需要POST数据
            if (!(parameters == null || parameters.Count == 0))
            {
                StringBuilder buffer = new StringBuilder();
                int i = 0;
                foreach (string key in parameters.Keys)
                {
                    if (i > 0)
                    {
                        buffer.AppendFormat("&{0}={1}", key, parameters[key]);
                    }
                    else
                    {
                        buffer.AppendFormat("{0}={1}", key, parameters[key]);
                    }
                    i++;
                }
                byte[] data = Encoding.UTF8.GetBytes(buffer.ToString());
                using (Stream stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
            }
            return request.GetResponse() as HttpWebResponse;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static String post(String url, String postdata)
        {
            try {
                HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                byte[] data = Encoding.UTF8.GetBytes(postdata.ToString());
                using (Stream stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                string outMessage = sr.ReadToEnd();
                sr.Close();
                return outMessage;
            } catch (Exception ex) {
                throw ex;
            }
        }


    }
}

  

要求

当前按照SDK的要求:

请求报文说明:     

1. 数据传输以HTTP POST方式发送,数据字符集一律采用UTF-8 

2. xmldata首先需要进行base64编码 

3. validation的效验方式采用 MD5(xmldata + partnerid + 密码),这里的加号为字符串连接符号。 

4. 所有参数最终均须在完成数据转换后进行URL编码。

 

请求报文详细解释: 

1.假设partnerid为YUNDA;密码为123456;xmldata内容为

<order></order>

2.xmldata经过base64编码以后变成PG9yZGVyPjwvb3JkZXI+

3.那么要签名的内容为PG9yZGVyPjwvb3JkZXI+YUNDA123456,经过md5后的内容就为f197e870a12528e38cb483b4e371f4ea

4.然后再对xmldata经过URL编码,得到字符串PG9yZGVyPjwvb3JkZXI%2B

5.同样需要对其他字段进行URL编码,否则可能会影响POST传递,具体请参见HTTP POST传输协议

6.最终要发送的数据为: partnerid=YUNDA&version=1.0&request=data&xmldata=PG9yZGVyPjwvb3JkZXI%2B&validation=f197e870a12528e38cb483b4e371f4ea

 

不拉不拉不拉,一大堆,大老爷们自己去看,这些数据转换的方法我直接贴出:

using System;
using System.Text;
using System.Web;
using System.IO;
using System.Xml.Serialization;

namespace ConsoleApplication1
{
    class DataTransform
    {
        /// <summary>
        /// 组装主体内容
        /// </summary>
        /// <param name="requestVO"></param>
        /// <returns></returns>
        public static String signData(RequestVO requestVO)
        {
            String xmldata = Convert.ToBase64String(System.Text.Encoding.GetEncoding("UTF-8").GetBytes(requestVO.xmldata));
            string validation = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(xmldata + requestVO.partnerid + requestVO.password, "MD5").ToLower();
            string signdata = "partnerid=" + requestVO.partnerid + "&version=" + requestVO.version + "&request=" + requestVO.request + "&xmldata=" + HttpUtility.UrlEncode(xmldata) + "&validation=" + validation;
            return signdata;
        }

        /// <summary>
        /// 内容数据转换XML
        /// </summary>
        /// <param name="type"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static String obj2Xml(Type type, Object obj)
        {
            XmlSerializer xml = new XmlSerializer(type);
            String xmldata = "";
            using (MemoryStream stream = new MemoryStream())
            {
                try
                {
                    xml.Serialize(stream, obj);
                    xmldata = Encoding.UTF8.GetString(stream.GetBuffer(), 0, (int)stream.Length);
                }
                catch (Exception)
                {
                    throw;
                }
            }
            return xmldata;
        }

        /// <summary>
        /// 内容清洗转换
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        public static string xmlformat(string xml) {
            try {

                System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
                doc.LoadXml(xml);

                System.IO.StringWriter sw = new System.IO.StringWriter();
                using (System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(sw))
                {
                    writer.Indentation = 2;  // the Indentation
                    writer.Formatting = System.Xml.Formatting.Indented;
                    doc.WriteContentTo(writer);
                    writer.Close();
                }
                return sw.ToString();
            } catch (Exception ex) {
                return xml;
            }
            
        }
    }
}

  

哈哈看了这么多了 咱还没看到请求电子面单的方法是吧  别急

这个类是我自己整合的在项目里的,大老爷们先看看有不足之处 指点指点,应该能看明白!哈哈!案例的是winfrom,这个类没有用上,方法我就不贴出来了,大佬自己去最底下载吧!!!

using Commons.BLL;
using Commons.Model;
using Commons.Settings;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
using System.Xml.Serialization;

namespace Commons.Helpers
{
    public class YunDaApiHelper
    {
        SettingService _settingService=new SettingService();
        /// <summary>
        /// 韵达电子面单请求url
        /// </summary>
        private static string _createYunDaUrl;
        /// <summary>
        /// 取消韵达电子面单url
        /// </summary>
        private static string _colseYunDaUrl;

        //韵达ID,密码
        private static string _partnerid;
        private static string _password;

        //发件人信息
        public static string FHCompany;
        public static string FHName;
        public static string FHMobile;
        public static string FHProvinceName;
        public static string FHCityName;
        public static string FHExpAreaName;
        public static string FHAddress;

        public YunDaApiHelper()
        {//_createYunDaUrl = "http://orderdev.yundasys.com:10110/cus_order/order_interface/interface_receive_order__mailno.php";//测试
            //_colseYunDaUrl = "http://orderdev.yundasys.com:10110/cus_order/order_interface/interface_cancel_order.php";//测试
            var settings = _settingService.LoadSetting<KdniaoSettings>();
            _createYunDaUrl = settings.CreateYunDaUrl;
            _colseYunDaUrl = settings.ColseYunDaUrl;
            FHCompany = settings.FHCompany;
            FHName = settings.FHName;
            FHMobile = settings.FHMobile;
            FHProvinceName = settings.FHProvinceName;
            FHCityName = settings.FHCityName;
            FHExpAreaName = settings.FHExpAreaName;
            FHAddress = settings.FHAddress;
            _partnerid = settings.YdPartnerId;
            _password = settings.YdPassword;
        }

        /// <summary>
        /// 申请韵达电子面单
        /// </summary>
        /// <param name="order"></param>
        /// <returns></returns>
        public YunDaResult CreateYunDaNo(Order order)
        {
            var model = new YDOrderModel();
            var send = new YDSender
            {
                name = FHName,//发货人名称
                company = FHCompany,//发货人公司
                mobile = FHMobile,//发货人移动电话或手机
                address = FHAddress,//发货人地址,需要将省市区划信息加上,例如:上海市,上海市,青浦区盈港东路7766号
                postcode = "510000", //邮编
                city = FHProvinceName + FHCityName + FHExpAreaName,//严格按照国家行政区划,省市区三级,逗号分隔。示例上海市,上海市,青浦区(cod订单必填)
                phone = "",//固话
                branch = ""
            };
            order.sender = send;
            model.order = order;
            try
            {
                var xml = Obj2Xml(typeof (YDOrderModel), model);
                var requestVo = new YunDaRequestModel
                {
                    xmldata = xml,
                    partnerid = _partnerid,
                    password = _password,
                    version = "1.0",
                    request = "data"
                };
                var data = SignData(requestVo);
                var result = Post(_createYunDaUrl, data);
                var msgBody = new XmlDocument();
                msgBody.LoadXml(result);
                var status = GetXmlValue(msgBody, "status");
                var dto = new YunDaResult
                {
                    status = Convert.ToInt32(status),
                    order_serial_no = GetXmlValue(msgBody, "order_serial_no"),
                    msg = GetXmlValue(msgBody, "msg"),
                    mail_no = GetXmlValue(msgBody, "mail_no")
                };
                return dto;

            }
            catch (Exception ex)
            {
                var dto = new YunDaResult
                {
                    status = (int) CustomBoolean.False,
                    msg = ex.ToString()
                };
                return dto;
            }
        }

        /// <summary>
        /// 取消韵达电子面单
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        public YunDaResult ColseYunDaNo(string xml)
        {
            var requestVo = new YunDaRequestModel
            {
                xmldata = Xmlformat(xml),
                partnerid = _partnerid,
                password = _password,
                version = "1.0",
                request = "cancel_order"
            };
            try
            {
                var data = SignData(requestVo);
                var result = Post(_colseYunDaUrl, data);
                var msgBody = new XmlDocument();
                msgBody.LoadXml(result);
                var dto = new YunDaResult
                {
                    status = Convert.ToInt32(GetXmlValue(msgBody, "status")),
                    order_serial_no = GetXmlValue(msgBody, "order_serial_no"),
                    msg = GetXmlValue(msgBody, "msg")
                };
                return dto;
            }
            catch (Exception ex)
            {
                var dto = new YunDaResult
                {
                    status = (int) CustomBoolean.False,
                    msg = ex.ToString()
                };
                return dto;
            }
        }







        #region 组装数据以及转化xml数据
        /// <summary>
        /// 组装主体内容
        /// </summary>
        /// <param name="requestVo"></param>
        /// <returns></returns>
        public static string SignData(YunDaRequestModel requestVo)
        {
            var xmldata = Convert.ToBase64String(System.Text.Encoding.GetEncoding("UTF-8").GetBytes(requestVo.xmldata));
            var validation = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(xmldata + requestVo.partnerid + requestVo.password, "MD5").ToLower();
            var signdata = "partnerid=" + requestVo.partnerid + "&version=" + requestVo.version + "&request=" + requestVo.request + "&xmldata=" + HttpUtility.UrlEncode(xmldata) + "&validation=" + validation;
            return signdata;
        }

        /// <summary>
        /// 内容数据转换XML
        /// </summary>
        /// <param name="type"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string Obj2Xml(Type type, object obj)
        {
            var xml = new XmlSerializer(type);
            var xmldata = "";
            using (var stream = new MemoryStream())
            {
                try
                {
                    xml.Serialize(stream, obj);
                    xmldata = Encoding.UTF8.GetString(stream.GetBuffer(), 0, (int)stream.Length);
                }
                catch (Exception)
                {
                    throw;
                }
            }
            return xmldata;
        }

        /// <summary>
        /// 内容清洗转换
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        public static string Xmlformat(string xml)
        {
            try
            {
                var doc = new System.Xml.XmlDocument();
                doc.LoadXml(xml);
                var sw = new System.IO.StringWriter();
                using (var writer = new System.Xml.XmlTextWriter(sw))
                {
                    writer.Indentation = 2;  // the Indentation
                    writer.Formatting = System.Xml.Formatting.Indented;
                    doc.WriteContentTo(writer);
                    writer.Close();
                }
                return sw.ToString();
            }
            catch (Exception ex)
            {
                return xml;
            }

        }
        #endregion

        #region Post数据请求
        public static HttpWebResponse Post(string url, IDictionary<string, string> parameters)
        {
            var request = WebRequest.Create(url) as HttpWebRequest;
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

            //如果需要POST数据
            if (!(parameters == null || parameters.Count == 0))
            {
                var buffer = new StringBuilder();
                var i = 0;
                foreach (var key in parameters.Keys)
                {
                    buffer.AppendFormat(i > 0 ? "&{0}={1}" : "{0}={1}", key, parameters[key]);
                    i++;
                }
                var data = Encoding.UTF8.GetBytes(buffer.ToString());
                using (var stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
            }
            return request.GetResponse() as HttpWebResponse;
        }

        public static string Post(string url, string postdata)
        {
            try
            {
                var request = WebRequest.Create(url) as HttpWebRequest;
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                var data = Encoding.UTF8.GetBytes(postdata.ToString());
                using (Stream stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
                var response = request.GetResponse() as HttpWebResponse;
                var sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                var outMessage = sr.ReadToEnd();
                sr.Close();
                return outMessage;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion

        #region MyRegion
        /// <summary>
        /// XML读取对应的值
        /// </summary>
        /// <param name="msgBody">xml</param>
        /// <param name="nodeName">节点名称</param>
        /// <returns>返回节点值</returns>
        public static string GetXmlValue(XmlDocument msgBody, string nodeName)
        {
            var fromUserName = msgBody.GetElementsByTagName(nodeName).Item(0);
            return fromUserName?.InnerText;
        }
        #endregion
    }
}

SettingService 这个是系统配置参数,应该没毛病哈哈!
so,下边咱来看看案例的界面
C#对接----韵达开发平台--取电子面单

账号:韵达的客户号

密码:是韵达二维码VIP客户端的《接口联调密码》

结语

案例很简单,但是有包含蛮多东东的,各位大佬只要是搞通一个,那估摸着就都没问题了!

链接:https://pan.baidu.com/s/1T3X8-TLorn5R8nZfpKkqOg 密码:m645      ------地址要是挂了,各位直接联系我哈!

好了!各位大老爷觉着这篇文章要是不错就点个赞咯