using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using DSWeb.MvcShipping.DAL.MsSysParamSet; using DSWeb.MvcShipping.Models.MsOpExpress; using InvokeWebService; namespace DSWeb.MvcShipping.DAL.MsOpExpressDAL { public class SFService { //顾客编码 private static string ClientCode = MsSysParamSetDAL.GetData("PARAMNAME='ClientCode'").PARAMVALUE; //电商加密私钥,校验码,注意保管,不要泄漏 private static string CheckWord = MsSysParamSetDAL.GetData("PARAMNAME='CheckWord'").PARAMVALUE; //月结卡号 private static string custid = MsSysParamSetDAL.GetData("PARAMNAME='custid'").PARAMVALUE; //顺丰运单查询接口 private static string OrderUrl = "http://bsp-oisp.sf-express.com/bsp-oisp/sfexpressService"; #region 路由查询 /// /// 路由查询 /// /// /// public static List GetHttpRouteSearch(RouteSearchService model) { //返回路由查询XML请求体 var xml = GetRoutexml(model); //MD5编码 var pass = Convert.ToBase64String(MD5(xml + CheckWord)); var result = GetRouteack(OrderUrl, "xml=" + xml + "&verifyCode=" + pass); return result; } /// /// 路由查询 /// /// URL地址 /// 编码后的请求体 /// private static List GetRouteack(string add, string post) { var client = new WebClient(); var sXml = ""; var rutoelist = new List(); try { var postData = Encoding.UTF8.GetBytes(post); client.Headers.Clear(); //采取POST方式必须加的header,如果改为GET方式的话就去掉这句话即可 client.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); sXml = Encoding.UTF8.GetString(client.UploadData(add, "POST", postData)); //判断返回响应体是否是ERR if (Convert.ToString(GetNodeValue(sXml, "Head")) == "ERR") { sXml = XElement.Parse(sXml).Value; rutoelist.Add(new RouteResponse {failMessage = XElement.Parse(sXml).Value}); } //将xml字符串转换为XML文档 var xmlDoc = XDocument.Parse(sXml); //获取 文档中子代元素 RouteResponse 的所有集合 var nodelist = xmlDoc.Descendants("RouteResponse"); if (nodelist != null) { //获取源集合中每个元素和子元素的集合 var pieceareas = nodelist.Elements(); foreach (var item in pieceareas) //循环添加到路由响应容器集合中 rutoelist.Add(new RouteResponse { //获取XML mailno 属性值 mailno = GetXmlNodeValue(sXml, "RouteResponse", "mailno"), Route = new Route { opcode = item.Attribute("opcode").Value, accept_address = item.Attribute("accept_address").Value, accept_time = item.Attribute("accept_time").Value, remark = item.Attribute("remark").Value } }); } } catch (Exception e) { client.Dispose(); rutoelist.Add(new RouteResponse {failMessage = XElement.Parse(sXml).Value}); return rutoelist; } client.Dispose(); return rutoelist; } /// /// 构建路由查询XML请求体 /// /// 路由查询请求模型 /// private static string GetRoutexml(RouteSearchService model) { string[] xmls = { "", "" + ClientCode + "", "", "", "", "" }; var xml = ""; foreach (var s in xmls) if (xml == "") xml = s; else xml += "\r\n" + s; return xml; } #endregion #region 下单接口 private static string CreateOrderXML(Order order,cargo cargo) { string[] xmls = { "", "" + ClientCode + "", "", "", "", "", "" }; var xml = ""; foreach (var s in xmls) if (xml == "") xml = s; else xml += "\r\n" + s; return xml; } /** * 获取顺丰下订单接口xml * @param params * @return */ private static string getOrderServiceRequestXml(Order order) { StringBuilder sb = new StringBuilder(); sb.Append(""); sb.Append("" + ClientCode + ""); sb.Append(""); sb.Append(" "); //货物信息 sb.Append(""); //sb.Append("count=1").Append(">"); sb.Append(""); sb.Append(""); sb.Append(""); sb.Append(""); return sb.ToString(); } public static MsOpSFPrint CreateOrder(Order order,cargo cargo) { order.custid = custid; //返回路由查询XML请求体 var xml = CreateOrderXML(order,cargo); //MD5编码 var pass = Convert.ToBase64String(MD5(xml + CheckWord)); var result = CreateOrderAction(OrderUrl, "xml=" + xml + "&verifyCode=" + pass); return result; } /// /// 下单 /// /// URL地址 /// 编码后的请求体 /// private static MsOpSFPrint CreateOrderAction(string add, string post) { var client = new WebClient(); var sXml = ""; var orderResult = new MsOpSFPrint(); try { //编码,尤其是汉字,事先要看下抓取网页的编码方式 var postData = Encoding.UTF8.GetBytes(post); client.Headers.Clear(); //采取POST方式必须加的header,如果改为GET方式的话就去掉这句话即可 client.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); sXml = Encoding.UTF8.GetString(client.UploadData(add, "POST", postData)); if (Convert.ToString(GetNodeValue(sXml, "Head")) == "ERR") { sXml = XElement.Parse(sXml).Value; orderResult.mailno = "ERR"; } //将xml字符串转换为XML文档 var xmlDoc = XDocument.Parse(sXml); //获取 文档中子代元素 RouteResponse 的所有集合 var nodelist = xmlDoc.Descendants("OrderResponse"); if (nodelist != null) { //获取源集合中每个元素和子元素的集合 //var pieceareas = nodelist.Elements(); orderResult.mailno = GetXmlNodeValue(sXml, "OrderResponse", "mailno"); orderResult.origincode = GetXmlNodeValue(sXml, "OrderResponse", "origincode"); orderResult.destcode = GetXmlNodeValue(sXml, "OrderResponse", "destcode"); //orderResult.filter_result = Convert.ToInt16(GetXmlNodeValue(sXml, "OrderResponse", "filter_result")); orderResult.orderid = GetXmlNodeValue(sXml, "OrderResponse", "orderid"); orderResult.rlsCode = orderResult.proCode = GetXmlNodeValue(sXml, "rls_info", "rls_code"); //orderResult.invoke_result = orderResult.proCode = GetXmlNodeValue(sXml, "rls_info", "invoke_result"); //orderResult.errorDesc = orderResult.proCode = GetXmlNodeValue(sXml, "rls_info", "errorDesc"); orderResult.proCode = GetXmlNodeValue(sXml, "rls_detail", "proCode"); orderResult.destRouteLabel = GetXmlNodeValue(sXml, "rls_detail", "destRouteLabel"); orderResult.destTeamCode = GetXmlNodeValue(sXml, "rls_detail", "destTeamCode"); orderResult.codingMapping = GetXmlNodeValue(sXml, "rls_detail", "codingMapping"); orderResult.codingMappingOut = GetXmlNodeValue(sXml, "rls_detail", "codingMappingOut"); orderResult.twoDimensionCode = GetXmlNodeValue(sXml, "rls_detail", "twoDimensionCode"); orderResult.abFlag = GetXmlNodeValue(sXml, "rls_detail", "abFlag"); } } catch (Exception e) { client.Dispose(); //rutoelist.Add(new RouteResponse {failMessage = XElement.Parse(sXml).Value}); //return rutoelist; } client.Dispose(); return orderResult; } #endregion #region XML处理 /// /// 读取XML资源中的指定节点内容 /// /// XML资源 /// 节点名称 /// 节点内容 public static object GetNodeValue(string source, string nodeName) { if (source == null || nodeName == null || source == "" || nodeName == "" || source.Length < nodeName.Length * 2) return null; var start = source.IndexOf("<" + nodeName + ">") + nodeName.Length + 2; var end = source.IndexOf(""); if (start == -1 || end == -1) return null; if (start >= end) return null; return source.Substring(start, end - start); } /// /// 获取xml任意节点中某个属性值 /// /// xml /// 节点名称 /// 属性名称 /// public static string GetXmlNodeValue(string strXml, string strNodeName, string strValueName) { try { var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(strXml); var xNode = xmlDoc.SelectSingleNode("//" + strNodeName + ""); var strValue = xNode.Attributes[strValueName].Value; return strValue; } catch (Exception ex) { //return ex.Message; return ""; } } /// /// 获取MD5 /// /// /// private static byte[] MD5(string str) { var result = Encoding.UTF8.GetBytes(str); MD5 md5 = new MD5CryptoServiceProvider(); var output = md5.ComputeHash(result); return output; } #endregion #region 路由推送 public static string RoutePushService(RoutePushService model) { var xml = GetPushxml(model); var pass = Convert.ToBase64String(MD5(xml + CheckWord)); var strData = "xml=" + xml + "&verifyCode=" + pass; var strHeaders = "Content-Type: application/x-www-form-urlencoded\r\n"; var bytePost = Encoding.UTF8.GetBytes(strData); var byteHeaders = Encoding.UTF8.GetBytes(strHeaders); var str = GetPushBack(OrderUrl, "xml=" + xml + "&verifyCode=" + pass); return str; } /// /// 构建路由推送XML /// /// 推送容器 /// private static string GetPushxml(RoutePushService model) { string[] xmls = { "", "", "", "orderid=‘" + model.orderid + "‘/>", "", "" }; var xml = ""; foreach (var s in xmls) if (xml == "") xml = s; else xml += "\r\n" + s; return xml; } /// /// 推送 /// /// URL /// 数据 /// private static string GetPushBack(string add, string post) { var pusthclient = new WebClient(); var sXml = ""; try { var postData = Encoding.UTF8.GetBytes(post); pusthclient.Headers.Clear(); //采取POST方式必须加的header,如果改为GET方式的话就去掉这句话即可 pusthclient.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); sXml = Encoding.UTF8.GetString(pusthclient.UploadData(add, "POST", postData)); //获取Head是否是ERR,若不是,直接返回OK if (Convert.ToString(GetNodeValue(sXml, "Head")) == "ERR") sXml = XElement.Parse(sXml).Value; else sXml = "OK"; } catch (Exception e) { sXml = e.Message; } pusthclient.Dispose(); return sXml; } #endregion } /// /// 路由请求实体 /// public class RouteSearchService { /// /// 查询号类别 1运单号查询 2 订单号查询 /// public string tracking_type { get; set; } /// /// 查询号 tracking_type=1 则此值是运单号 tracking_type为1=2 此值是订单号 /// public string tracking_number { get; set; } /// /// 1 标准路由查询 2定制路由查询 /// public string method_type { get; set; } /// /// 收件人或寄件人手机号后四位 /// public string check_phoneNo { get; set; } } /// /// 路由返回报文实体 /// public class RouteResponse { public string mailno { get; set; } public Route Route { get; set; } public string failMessage { get; set; } } /// /// 路由信息实体 /// public class Route { public string accept_time { get; set; } public string accept_address { get; set; } public string remark { get; set; } public string opcode { get; set; } } /// /// 下单实体 /// public class Order { //客户订单号,必填 public string orderid { get; set; } //顺丰运单号,条件 public string mailno { get; set; } //寄件方公司名称,条件 public string j_company { get; set; } //寄件方联系人,条件 public string j_contact { get; set; } //寄件方联系电话,条件 public string j_tel { get; set; } //寄件方手机,否 public string j_mobile { get; set; } //寄件方所在省份,否 public string j_province { get; set; } //寄件方所在城市名称,否 public string j_city { get; set; } //寄件方所在区县,否 public string j_county { get; set; } //寄件方详细地址,条件 public string j_address { get; set; } //到件方公司名称,必填 public string d_company { get; set; } //到件方联系人,必填 public string d_contact { get; set; } //到件方联系电话,必填 public string d_tel { get; set; } //到件方手机,否 public string d_mobile { get; set; } //到件方所在省份,否 public string d_province { get; set; } //到件方所在城市名称,否 public string d_city { get; set; } //到件方所在县区,否 public string d_county { get; set; } //到件方详细地址,是 public string d_address { get; set; } //月结号,否 public string custid { get; set; } //付款方式,否 public int pay_method { get; set; } //快件产品编码,否 public string express_type { get; set; } //快件包裹数,否 public int parcel_quantity { get; set; } //客户订单货物总长,否 public decimal cargo_length { get; set; } //客户订单货物总宽,否 public decimal cargo_width { get; set; } //客户订单货物高度,否 public decimal cargo_height { get; set; } //总体积,否 public decimal volume { get; set; } //订单货物总重量,否 public decimal cargo_total_weight { get; set; } //要求上门开始时间,否 public DateTime sendstarttime { get; set; } //是否通过手持端通知顺丰快递员,否 public int is_docall { get; set; } //是否要求签回单号,否 public string need_return_tracking_no { get; set; } //顺丰签回运单号,否 public string return_tracking { get; set; } //温度范围类型,条件 public int temp_range { get; set; } //业务模板编码,否 public string template { get; set; } //备注,否 public string remark { get; set; } //客户自取,否 public int oneself_pickup_flg { get; set; } //特殊派送类型,否 public string special_delivery_type_code { get; set; } //特殊派送类型表述,否 public string special_delivery_value { get; set; } //实名认证流水号,否 public string realname_num { get; set; } //签回单路由返回,否 public int routelabelForReturn { get; set; } //路由标签查询服务,否 public int routelabelService { get; set; } //是否使用国家统一面单号,否 public int is_unified_waybill_no { get; set; } } public class cargo { //货物名称,必填 public string name { get; set; } //货物数量,条件 public int count { get; set; } } public class OrderResponse { //客户订单号,必填 public string orderid { get; set; } //顺丰运单号,否 public string mailno { get; set; } //顺丰签回单服务运单号,否 public string return_tracking_no { get; set; } //原寄地区域代码,否 public string origincode { get; set; } //目的地区域代码,否 public string destcode { get; set; } //筛单结果:1:人工确认,2:可收派,3:不可以收派 public int filter_result { get; set; } //若filter_result为3则为必填,1:收方超范围,2:寄方超范围,3:其他原因 public string remark { get; set; } //代理单号 public string agentMailno { get; set; } //地址映射码 public string mapping_mark { get; set; } //url public string url { get; set; } //用于第三方支付的url public string PaymentLink { get; set; } public rls_info rls_info { get; set; } } /// /// 下单元素响应 /// public class rls_info { public string invoke_result { get; set; } public string rls_code { get; set; } public string errorDesc { get; set; } public rls_detail rls_detail { get; set; } } public class rls_detail { public string waybillNo { get; set; } //原寄地中转场 public string sourceTransferCode { get; set; } //原寄地城市代码 public string sourceCityCode { get; set; } //原寄地网点代码 public string sourceDeptCode { get; set; } //原寄地单元代码 public string sourceTeamCode { get; set; } //目的地城市代码 public string deptCityCode { get; set; } //目的地网点代码 public string deptDeptCode { get; set; } //目的地代码映射 public string destDeptCodeMapping { get; set; } //目的地单元代码 public string destTeamCode { get; set; } //目的地单元区域码映射 public string destTeamCodeMapping { get; set; } //目的地中转场 public string destTransferCode { get; set; } //打单时的标签信息 public string destRouteLabel { get; set; } //产品名称 public string proName { get; set; } //快件内容 public string cargoTypeCode { get; set; } //时效代码 public string limitTypeCode { get; set; } //产品类型 public string expressTypeCode { get; set; } //入港映射码 public string codingMapping { get; set; } //出港映射码 public string codingMappingOut { get; set; } //xb标志 public string xbFlag { get; set; } //打印标志 public string printFlag { get; set; } //二维码 public string twoDimensionCode { get; set; } //时效类型 public string proCode { get; set; } //打印图标 public string printIcon { get; set; } //ab标 public string abFlag { get; set; } //时效类型 public string errMsg { get; set; } //目的地口岸代码 public string destPortCode { get; set; } //目的地国别 public string destCountry { get; set; } //目的地邮编 public string destPostCode { get; set; } //总价值 public string goodsValueTotal { get; set; } //币种 public string currencySymbol { get; set; } //件数 public string goodsNumber { get; set; } //校验码 public string checkCode { get; set; } } /// /// 路由推送模型 /// public class RoutePushService { /// /// 路由节点信息编号,每一个id 代表一条不同的路由节点信息 /// public int id { get; set; } /// /// 顺丰运单号 /// public string mailno { get; set; } /// /// 客户订单号 /// public string orderid { get; set; } /// /// 路由节点产生的时间,格式:YYYY-MM-DDHH24:MM:SS /// public DateTime acceptTime { get; set; } /// /// 路由节点发生的城市 /// public string acceptAddress { get; set; } = "深圳"; /// /// 路由节点具体描述 /// public string remark { get; set; } = "上门收件"; /// /// 路由节点操作码 /// public string opCode { get; set; } = "50"; } }