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

引子

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

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

当然附上地址:http://open.yundasys.com/index.php?g=&m=ApiTools&a=exm

还有接口的一些SDK文件地址,这个就各位观众大老爷们自己去看了:http://open.yundasys.com/index.php?g=&m=ApiTools&a=apps&id=14

 

解决方案

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

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,下边咱来看看案例的界面

账号:韵达的客户号

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

结语

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

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

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

 
posted @ 2018-06-13 14:53 快舔包我很肥 阅读(...) 评论(...) 编辑 收藏