微信支付接口之心酸

微信接口,对于某些人来说,很容易,宝宝自己尝试了一下,瞬间感觉泪奔呀,唉。

首先,统一下单接口

        [HttpPost]
        [Route("~/api/WXPay/UnifiedOrder")]
        public HttpResponseMessage UnifiedOrder()
        {
            try
            {
                NameValueCollection param = Request.Content.ReadAsFormDataAsync().Result;
                string body = param["body"].ToString();//简单描述
                string out_trade_no = param["out_trade_no"].ToString();
                string total_fee = param["total_fee"].ToString();
                string spbill_create_ip = param["spbill_create_ip"].ToString();
                var stringADict = new Dictionary<string, string>();
                stringADict.Add("appid", "这里是公众号ID");
                stringADict.Add("mch_id", "商户号");
                stringADict.Add("device_info", device_info);
                stringADict.Add("nonce_str", CreateNonce_str());
                stringADict.Add("body", body);
                stringADict.Add("out_trade_no", out_trade_no);
                stringADict.Add("total_fee", total_fee);
                stringADict.Add("spbill_create_ip", spbill_create_ip);
                stringADict.Add("notify_url", "回调函数");
                stringADict.Add("trade_type", "APP");
                var sign = Sign(stringADict, "签名字符串");//生成签名字符串
                var postdata = GeneralPostdata(stringADict, sign);
                var url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
                var client = new HttpClient();
                var result = client.PostAsync(url, new StringContent(postdata)).Result;
                if (!result.IsSuccessStatusCode) return null;
                dynamic doc = new DynamicXml(result.Content.ReadAsStringAsync().Result);
                JObject obj = new JObject();
                var a = doc.return_code.Value;
                var c = doc.return_msg.Value;
                if (doc.return_code.Value == "SUCCESS" && doc.result_code.Value == "SUCCESS")
                {
                    obj.Add("prepay_id", doc.prepay_id.Value);
                    obj.Add("trade_type", doc.trade_type.Value);
                    obj.Add("sign", doc.sign.Value);
                    obj.Add("nonce_str", doc.nonce_str.Value);

                    obj.Add("result_code", doc.result_code.Value);
                    obj.Add("return_code", doc.return_code.Value);
                    obj.Add("return_msg", doc.return_msg.Value);
                    obj.Add("RetCode", 0);
                    obj.Add("RetMsg", "");
                }
                else
                {
                    obj.Add("RetCode", -1);
                    obj.Add("doc", doc.return_code.ToString() + doc.return_msg.ToString());
                }
                return Request.CreateResponse(obj);
            }
            catch (Exception e)
            {
                JObject obj = new JObject();
                obj.Add("RetCode", "-1");
                obj.Add("ErrorDescription", e.ToString());
                obj.Add("RetMsg", "错误代码:" + Guid.NewGuid().ToString());
                return Request.CreateResponse(obj);
            }
        }

  在这里,必须要说明的是DynamicXml,在这个动态读取XML的时候,可坑死宝宝了。

 public class DynamicXml : DynamicObject, IEnumerable
    {
        private readonly List<XElement> _elements;
        public DynamicXml(string text)
        {
            var doc = XDocument.Parse(text);
            _elements = new List<XElement> { doc.Root };
        }

        protected DynamicXml(XElement element)
        {
            _elements = new List<XElement> { element };
        }

        protected DynamicXml(IEnumerable<XElement> elements)
        {
            _elements = new List<XElement>(elements);
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = null;
            if (binder.Name == "Value")
                result = _elements[0].Value;
            else if (binder.Name == "Count")
                result = _elements.Count;
            else
            {
                var attr = _elements[0].Attribute(XName.Get(binder.Name));
                if (attr != null)
                    result = attr;
                else
                {
                    var items = _elements.Descendants(XName.Get(binder.Name));
                    if (items == null || items.Count() == 0) return false;
                    result = new DynamicXml(items);
                }
            }
            return true;
        }

      


        public IEnumerator GetEnumerator()
        {
            foreach (var element in _elements)
                yield return new DynamicXml(element);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="binder"></param>
        /// <param name="indexes"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
        {
            int ndx = (int)indexes[0];
            result = new DynamicXml(_elements[ndx]);
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            StringWriter message = new StringWriter();
            foreach (var item in _elements)
                message.WriteLine("{0}:	{1}", item.Document,
                item.Value);
            return message.ToString();
        }
    }

  因为刚开始没有加上ToString和TryGetIndex的重写,然后呢,解析了一天,都不知道哪里的错。唉

OK,微信回调接口

        [HttpPost]
        [Route("~/api/WXPay/Notify")]
        public HttpResponseMessage Notify()
        {
            try
            {

                byte[] a = Request.Content.ReadAsByteArrayAsync().Result;
                string b = Encoding.UTF8.GetString(a);
                var sParam = GetRequestPost(b);

                if (sParam.Count <= 0)
                {
                    throw new ArgumentNullException();
                }
                JObject obj = new JObject();
                obj.Add("RetCode", 0);
                obj.Add("RetMsg", "");

                if (sParam["return_code"] == "SUCCESS" && sParam["result_code"] == "SUCCESS")
                {
                    var sign = sParam["sign"];
                    var signValue = Sign(sParam, "签名字符串");
                    bool isVerify = sign == signValue;
                    if (isVerify)
                    {
                        var out_trade_no = sParam["out_trade_no"];
                        //具体的后期业务操作
                    }
                    obj.Add("return_code", "success");
                }
                else
                {
                    obj.Add("return_code", "fail");
                }
                return Request.CreateResponse(HttpStatusCode.OK, obj);
            }
            catch (ArgumentNullException e)
            {
                JObject obj = new JObject();
                obj.Add("RetCode", "-1");
                obj.Add("RequestMsg", "暂无参数!");

                return Request.CreateResponse(obj);
            }
            catch (Exception e)
            {
                JObject obj = new JObject();
                obj.Add("RetCode", "-1");
                obj.Add("ErrorDescription", e.ToString());
                obj.Add("RetMsg", "错误代码:" + Guid.NewGuid().ToString());
                return Request.CreateResponse(obj);
            }
        }

  对于这里的GetRequestPost方法,其实就是组合生成一个标准的xml字符串。

        private SortedDictionary<string, string> GetRequestPost(string xml)
        {
            SortedDictionary<string, string> sArray = new SortedDictionary<string, string>();

            dynamic resultXml = new DynamicXml(xml);

            sArray.Add("appid", resultXml.appid.Value);
            sArray.Add("bank_type", resultXml.bank_type.Value);
            sArray.Add("cash_fee", resultXml.cash_fee.Value);
            sArray.Add("fee_type", resultXml.fee_type.Value);

            sArray.Add("is_subscribe", resultXml.is_subscribe.Value);
            sArray.Add("mch_id", resultXml.mch_id.Value);
            sArray.Add("nonce_str", resultXml.nonce_str.Value);
            sArray.Add("openid", resultXml.openid.Value);

            sArray.Add("out_trade_no", resultXml.out_trade_no.Value);
            sArray.Add("time_end", resultXml.time_end.Value);
            sArray.Add("total_fee", resultXml.total_fee.Value);
            sArray.Add("transaction_id", resultXml.transaction_id.Value);


            sArray.Add("trade_type", resultXml.trade_type.Value);
            sArray.Add("sign", resultXml.sign.Value);
            sArray.Add("result_code", resultXml.result_code.Value);
            sArray.Add("return_code", resultXml.return_code.Value);


            return sArray;
        }

  附,后面的辅助方法,包含签名生成工具等。

        public static string GeneralPostdata(IDictionary<string, string> postdataDict, string sign)
        {
            var sb2 = new StringBuilder();
            sb2.Append("<xml>");
            foreach (var sA in postdataDict.OrderBy(x => x.Key))
            {
                sb2.Append("<" + sA.Key + ">")
                   .Append(Transfer(sA.Value))
                   .Append("</" + sA.Key + ">");
            }
            sb2.Append("<sign>").Append(sign).Append("</sign>");
            sb2.Append("</xml>");
            return sb2.ToString();
        }

        public static string Transfer(string instr)
        {
            if (instr == null) return "";
            return instr.Replace("&", "&").Replace("<", "<")
                        .Replace(">", ">").Replace(""", """);
        }


        /// <summary>
        /// 生成签名
        /// 签名在线验证工具:
        /// http://mch.weixin.qq.com/wiki/tools/signverify/
        /// </summary>
        /// <param name="stringADict">参与签名生成的参数列表</param>
        /// <param name="partnerKey">商家私钥</param>
        /// <returns></returns>
        public static string Sign(IDictionary<string, string> stringADict, string partnerKey)
        {
            var sb = new StringBuilder();
            foreach (var sA in stringADict.OrderBy(x => x.Key))
            {
                if (string.IsNullOrEmpty(sA.Value)) continue;
                if (string.Compare(sA.Key, "sign", true) == 0) continue; 
                sb.Append(sA.Key).Append("=").Append(sA.Value).Append("&");
            }
            var string1 = sb.ToString();
            sb.Append("key=").Append(partnerKey);
            var stringSignTemp = sb.ToString();
            var sign = MD5(stringSignTemp, "UTF-8").ToUpper();
            return sign;
        }

        public static string MD5(string encypStr, string charset = "UTF-8")
        {
            string retStr;
            MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider();
            byte[] inputBye;
            byte[] outputBye;
            try
            {
                inputBye = Encoding.GetEncoding(charset).GetBytes(encypStr);
            }
            catch
            {
                inputBye = Encoding.GetEncoding("GB2312").GetBytes(encypStr);
            }
            outputBye = m5.ComputeHash(inputBye);

            retStr = System.BitConverter.ToString(outputBye);
            retStr = retStr.Replace("-", "").ToUpper();
            return retStr;
        }

  OK,只是一个简单的记录,可以直接套用的,当然,对于.net来说,特别注意的就是那个DynamicXML那个类,太尼玛坑爹了,百毒了半天,然后看了半天,终于晓得问题了,唉。不喜勿喷。谢谢

      其中,很多包含借鉴网上的东西,如有版权牵扯,请及时联系本人,谢谢。

原文地址:https://www.cnblogs.com/JeffController/p/5531494.html