1. 程式人生 > >微信公眾號付款asp.net版本

微信公眾號付款asp.net版本

1.在需要支付的頁面先獲取code

 protected void Page_Load(object sender, EventArgs e)
    {
        code = "" + HttpContext.Current.Request.Params["code"];

if (string.IsNullOrEmpty(code))
{
string appid = “你的appid”;
var uri = “需要回傳引數的url,可以是當前頁面”;
string url = GetCodeUrl(appid, uri, null);
Response.Redirect(url);

        }

        }

 public string GetCodeUrl(string Appid, string redirect_uri, string formId)
    {
        return string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope=snsapi_userinfo&state={2}#wechat_redirect", Appid, redirect_uri, formId);
    }

2.寫前端支付按鈕的js事件

    <input type="button" id="btnPay" onclick="pay();" value="立即支付"  runat="server" />
     <script type="text/javascript">

    function getParam(name) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
        var r = window.location.search.substr(1).match(reg);
        if (r != null) return unescape(r[2]); return null;
    }

function pay()
    {
       if (typeof WeixinJSBridge == "undefined") {
            alert("請在微信中開啟");
           return;
       }
        var code = getParam("code"); //獲取  code  回撥的頁面獲取Code
        var orderid = ”訂單號“;
        var totalprice = 訂單價格; 
        var url = "處理引數的後臺頁面";
        $.post(url, { code: code, orderid: orderid, total: totalprice }, function (data) {
            if (data.err_msg) {
                alert(data.err_msg);
                return;
            }
            //alert(data.appId);
            var invokeData = {
                "appId": data.appId, //公眾號名稱,由商戶傳入
                "timeStamp": data.timeStamp, //時間戳,自1970年以來的秒數
                "nonceStr": data.nonceStr, //隨機串32個位元組以下
                "package": data.package, //訂單詳情擴充套件字串字串型別,4096個位元組以下是商戶將訂單資訊組成該字串,具體組成方案參見介面使用說明中package組包幫劣;由商戶按照規範拼接後傳入;
                "signType": data.signType, //微信簽名方式:目前只支援MD5  
                "paySign": data.paySign//微信簽名
            };

            WeixinJSBridge.invoke(
                           'getBrandWCPayRequest', invokeData,
                           function (res) {
                               if (res.err_msg == "get_brand_wcpay_request:ok") {
                                   alert("支付完成");

                               }     // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在使用者支付成功後返回    ok,但並不保證它絕對可靠。  
                               else if (res.err_msg == "get_brand_wcpay_request:cancel") {
                                   alert("使用者取消支付!");
                               } else {
                                   alert("支付失敗!" + res.err_msg);
                               }
                           });
        }, "json");
    }
</script>”

3.第2個步驟中提到的後臺處理引數的頁面根據2中獲取的code引數獲取openid

public void ProcessRequest(HttpContext context)
    {
        try
        {
            string code = "" + context.Request.Params["code"];
            JavaScriptSerializer ser = new JavaScriptSerializer();
            if (string.IsNullOrEmpty(code))
            {
                var json = ser.Serialize(new { err_msg = "非法操作" });
                context.Response.Write(json);
            }
            string orderid = context.Request.Params["orderid"];
            string totalprice = context.Request.Params["total"];
            //獲取openId
            string openId = GetOpenId(code);
            string resultXml;
            try
            {
                OrderSuccCallbackData callbackData =new WXGZPay().WXOrder(openId, orderid, totalprice, out resultXml);
                string responseStr = ser.Serialize(callbackData);
                HttpContext.Current.Response.Write(responseStr);
            }
            catch
            {
                insertlog("微信支付開始封包!new WXGZPay().WXOrder失敗");
            }


        }
        catch (Exception e)
        {
            JavaScriptSerializer ser = new JavaScriptSerializer();
            HttpContext.Current.Response.Write(ser.Serialize(new { err_msg = e.Message }));
        }
    }

private string GetOpenId(string code)
    {
        string appid = "你的appid";
        string secret = "你的secret";
        string url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code";
        string result = HttpGet(url);
        JavaScriptSerializer ser = new JavaScriptSerializer();
        TokenCls cls = ser.Deserialize<TokenCls>(result);
        return cls.openid;
    }

private string HttpGet(string Url, string postDataStr = "")
    {
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (postDataStr == "" ? "" : "?") + postDataStr);
        request.Method = "GET";
        request.ContentType = "text/html;charset=UTF-8";
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        Stream myResponseStream = response.GetResponseStream();
        StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
        string retString = myStreamReader.ReadToEnd();
        myStreamReader.Close();
        myResponseStream.Close();
        return retString;
    }

 [Serializable]
    class TokenCls
    {
        public string access_token { get; set; }
        public int expires_in { get; set; }
        public string refresh_token { get; set; }
        public string openid { get; set; }
        public string scope { get; set; }
        public string unionid { get; set; }
    }

4.第3步驟中WXGZPay().WXOrder頁面引數處理

public OrderSuccCallbackData WXOrder(string openId, string orderid,string totalprice,out string resultXml)
    {
        //訂單號加隨機數,因為微信介面不允許同一個訂單號處理兩次以上
        string orderNum = orderid + new Random().Next(1000,10000).ToString();
        string payFee = totalprice;
        //客戶端ip地址
        string clientIp = "客戶端ip地址";      
        //128個字以內的說明文字
        string body = "訂單號:" + orderid.Remove(orderid.Length - 4);
        //回撥地址
        string callbackUrl = “回撥頁面url”;

        string timeStamp = GetTimespanSince1970();
        //微信統一訂單下單地址
        string postUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";

        //構造統一訂單引數
        Dictionary<string, string> parms = BuildParams(openId, orderNum, payFee, clientIp, body, callbackUrl);

        //對統一訂單引數進行ascii排序
        Dictionary<string, string> orderParms = OrderParams(parms);
        //將排序後的訂單引數轉換成url引數形式
        string urlParms = BuildUrlParams(orderParms);
        //url地址後加上key
        urlParms = urlParms + "&key=" + appKey;
        //把url地址進行md5加密作為sign
        var sign = Md5Encrypt(urlParms).ToUpper();

        //在將簽名sign新增到提交引數中
        orderParms.Add("sign", sign);

        //////////////此時正式提交的引數構造完畢//////////////////
        string xmlString = DictionaryToXML(orderParms);

        //post提交資料到微信統一訂單下單API
        resultXml = PostResponse(postUrl, xmlString);

        //XML解析,並獲取prepay_id,
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(resultXml);
        string return_code = doc.GetElementsByTagName("return_code").Item(0).InnerText;
        string result_code = doc.GetElementsByTagName("result_code").Item(0).InnerText;
        string package = string.Empty;
        if (return_code.Equals("SUCCESS") && result_code.Equals("SUCCESS"))
        {
            string prepay_id = doc.GetElementsByTagName("prepay_id").Item(0).InnerText;
            package = "prepay_id=" + prepay_id;
        }


        OrderSuccCallbackData data = new OrderSuccCallbackData()
        {
            appId = appid,
            nonceStr = orderParms["nonce_str"],
            package = package,
            //paySign = sign,
            signType = "MD5",
            timeStamp = timeStamp
        };
        data.paySign = GetJSApiSign(data.appId, data.nonceStr, data.package, data.timeStamp);
        return data;
    }

     public string GetJSApiSign(string appId, string nonceStr, string package, string timeStamp)
    {
      Dictionary<string, string> parms = new Dictionary<string, string>();
                parms.Add("appId", appId);
        parms.Add("nonceStr", nonceStr);
        parms.Add("package", package);
        parms.Add("signType", "MD5");
        parms.Add("timeStamp", timeStamp);

        //排序引數
        parms = parms.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value);

        string urlParms = BuildUrlParams(parms);

        //url地址後加上key
        urlParms = urlParms + "&key=" + appKey;

        //把url地址進行md5加密作為sign
        var sign = Md5Encrypt(urlParms).ToUpper();

        //在將簽名sign新增到提交引數中
        parms.Add("sign", sign);

        return sign;
    }

  private string PostResponse(string url, string param)
    {
        string pi_strParm = param;
        ServicePointManager.Expect100Continue = false;//post提交資料時,客戶端會先詢問伺服器是否會處理資料,若不處理,則不提交。此設定為不詢問,直接提交資料。
        Encoding t_Encoding = Encoding.UTF8;
        Uri t_Uri = new Uri(url);
        byte[] paramBytes = t_Encoding.GetBytes(pi_strParm);

        WebRequest t_WebRequest = WebRequest.Create(t_Uri);
        t_WebRequest.Timeout = 100000;
        t_WebRequest.ContentType = "application/x-www-form-urlencoded";
        t_WebRequest.Method = "POST";
        using (Stream t_REStream = t_WebRequest.GetRequestStream())
        {
            t_REStream.Write(paramBytes, 0, paramBytes.Length);
        }
        WebResponse t_webResponse = t_WebRequest.GetResponse();
        using (StreamReader t_StreamReader = new StreamReader(t_webResponse.GetResponseStream(), Encoding.UTF8))
        {
            string returnStr = t_StreamReader.ReadToEnd();
            return returnStr;
        }
    }

private string GetTimespanSince1970()
{
double totalSecs = (DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds;
return Convert.ToInt32(totalSecs).ToString();
}

     private string DictionaryToXML(Dictionary<string, string> parms)
    {
            StringBuilder sb = new StringBuilder();
        sb.Append("<xml>");

        foreach (KeyValuePair<string, string> item in parms)
        {
            string pre = "<" + item.Key + ">";
            string end = "</" + item.Key + ">";
            string line = pre + item.Value + end;
            sb.Append(line);
        }
        sb.Append("</xml>");
        return sb.ToString();
    }

 private Dictionary<string, string> BuildParams(
        string openId,
        string orderNum,
        string payFee,
        string clientIp,
        string body,
        string callbackUrl)
    {
        Dictionary<string, string> parms = new Dictionary<string, string>();
        parms.Add("openid", openId);
        parms.Add("appid", appid);
        parms.Add("mch_id", mch_id);
        parms.Add("nonce_str", Md5Encrypt(new Random().Next().ToString()));
        parms.Add("body", body);
        parms.Add("out_trade_no", orderNum);
        parms.Add("total_fee", payFee);
        parms.Add("spbill_create_ip", clientIp);
        parms.Add("notify_url", callbackUrl);
        parms.Add("trade_type", "JSAPI");
        return parms;
    }

  private Dictionary<string, string> OrderParams(Dictionary<string, string> parms)
        {
            Dictionary<string, string> orderParams = parms.OrderBy(p => p.Key).ToDictionary(p => p.Key, q => q.Value);
        return orderParams;
    }

  private string BuildUrlParams(Dictionary<string, string> parms)
    {
        StringBuilder sb = new StringBuilder();
        foreach (KeyValuePair<string, string> item in parms)
        {
            sb.Append(item.Key + "=" + item.Value + "&");
        }
        string sbStr = sb.ToString();
        return sbStr.TrimEnd('&');
    }

private string Md5Encrypt(string sourceStr)
    {
        MD5 md5 = new MD5CryptoServiceProvider();
        var data = Encoding.UTF8.GetBytes(sourceStr);
        var encs = md5.ComputeHash(data);
        return BitConverter.ToString(encs).Replace("-", "");
    }

 public class OrderSuccCallbackData
    {
        /// <summary>
        /// appip
        /// </summary>
        public string appId { get; set; }

        /// <summary>
        /// 1970年時間戳
        /// </summary>
        public string timeStamp { get; set; }

        /// <summary>
        /// 隨機碼
        /// </summary>
        public string nonceStr { get; set; }

        /// <summary>
        /// 預付id   prepay_id=123456789
        /// </summary>
        public string package { get; set; }

        /// <summary>
        /// 簽名型別,MD5
        /// </summary>
        public string signType { get; set; }

        /// <summary>
        /// 簽名
        /// </summary>
        public string paySign { get; set; }

}
    5.在回撥頁面進行訂單處理。

    希望對那個需要的你有所幫助。。