C#-MVC-微信和支付寶H5支付開發及Demo

微信和支付寶H5支付

最近開發任務遇到了一個要在手機瀏覽器裏面調起微信和支付寶去支付的開發需求,以前都是做的掃碼支付或者JSAPI都是在軟件內部支付的,沒遇到過在自己瀏覽器內喚醒微信或者支付寶的支付這種開發在開發的過程中遇到了許多問題和坑點這裏就一一寫進文章裏面了

首先放上支付寶和微信支付的開發文檔

支付寶手機網頁支付
微信H5支付

由於是教程貼我們從一個新建的MVC項目開始

MVC

首先編寫一個H5支付的頁面
選擇支付
代碼如下所示:


@{
    ViewBag.Title = "H5支付頁";
    Layout = null;
}
<body>
    <script src="~/Scripts/jquery-3.4.1.js"></script>
    <script src="~/Scripts/bootstrap.min.js"></script>
    <link href="~/Content/bootstrap.min.css" rel="stylesheet" />
    <script src="~/Content/layer/layer.js"></script>
    <link href="~/Content/layer/theme/default/layer.css" rel="stylesheet" />
    
    <style>
        ul li {
            list-style: none;
            font-size: 40px;
            margin-bottom: 20px;
        }

        input {
            height: 50px !important;
            width: 50px !important;
            margin-left: 5%;
        }

        .head {
            background-color: darkblue;
            height: 100px;
            font-size: 40px;
            color: white;
            text-align: center;
        }

        .pay {
            width: 50%;
            margin: 5% 25%;
            border: 3px dashed lightgray;
            border-radius: 15px;
        }

        .btncolor {
            border-radius: 25px;
            background-color: #1E90FF;
            color: white;
        }
    </style>
    <form id="alitopay" action="支付寶後臺處理網址" onsubmit="return sure();" method="post">

        <div style="text-align:center;margin:50px 0 0 0;font-size:40px">請選擇支付方式</div>
        <img src="~/Images/weixin.png" class="pay" value="1" />

        <img id="zhifubao" src="~/Images/zhifubao.png" class="pay" value="2" />

        <div style="position:fixed;bottom:15%;width:100%;">
            <button class="btncolor" style="height:130px;margin:250px 5% 5% 5%;font-size:40px;width:90%;">確認支付</button>
        </div>

    </form>
</body>

<script>
    var paytype = "";
    function bordernone() {
        $(".pay").css("border", " 3px dashed lightgray");

    }
    $(".pay").click(function () {
        bordernone();
        $(this).css("border", "5px solid #1E90FF");
        paytype = $(this).attr("value");
    });
    function sure() {
        var Guid = $("#Guid").val();
        //paytype = $('input:radio:checked').val();
        if (paytype === "" || paytype === undefined) {
            layer.msg('<div style="font-size: 40px;margin-top:20px;">' + '請選擇支付方式' + '</div>',
                {
                    area: ["400px", "100px"]
                });
            return false;
        } else if (paytype === 2) {//支付寶
            $('#alitopay').submit();
            return true;
        } else if (paytype == 1) {//微信
            $.ajax({
                type: 'Post',
                url: '微信後臺處理網址',
                data: { Guid: Guid },
                dataType: 'json',
                success: function (result) {
                    if (result.id > 0) {
                        window.location.href = result.result;
                    }
                }
            });
            return false;
        }
    }
    $(document).ready(function () {
        $('.pay').trigger("click");
    })
</script>


這裏我們首先講解微信支付
微信支付爲了簡單快捷我們用了盛派的SDK引入步驟如下
1.首先右鍵項目選擇管理Nuget程序包
在這裏插入圖片描述

安裝盛派的dll

需要值得注意的是我們要安裝2個dll一個Senparc.Weixin一個 Senparc.Weixin.TenPay
Pay

安裝完成後我們在跟目錄的web.config添加以下內容

 <!-- 微信支付V3 -->
    <add key="TenPayV3_MchId" value="你的微信商戶ID" />
    <add key="TenPayV3_Key" value="你的微信商戶密鑰" />
    <add key="TenPayV3_AppId" value="你的微信平臺APPID" />
    <add key="TenPayV3_AppSecret" value="你的微信平臺AppSecret" />
    <add key="TenPayV3_TenpayNotify" value="支付完成後回調通知地址" />

在這裏插入圖片描述

配置web.config後我們還要修改Global.asax

            //設置全局Debug 狀態
            var isGLobalDebug = true;
            //全局設置參數,將被儲存到 Senparc.CO2NET.Config.SenparcSetting
            var senparcSetting = SenparcSetting.BuildFromWebConfig(isGLobalDebug);
            //也可以通過這種方法在程序任意位置設置全局 Debug 狀態:
            //Senparc.CO2NET.Config.IsDebug = isGLobalDebug;


            //CO2NET 全局註冊,必須!!
            IRegisterService register = RegisterService.Start(senparcSetting).UseSenparcGlobal();

            //設置微信 Debug 狀態
            var isWeixinDebug = true;
            //全局設置參數,將被儲存到 Senparc.Weixin.Config.SenparcWeixinSetting
            var senparcWeixinSetting = SenparcWeixinSetting.BuildFromWebConfig(isWeixinDebug);
            //也可以通過這種方法在程序任意位置設置微信的 Debug 狀態:
            //Senparc.Weixin.Config.IsDebug = isWeixinDebug;

            //微信全局註冊,必須!!
            register.UseSenparcWeixin(senparcWeixinSetting, senparcSetting)
            .RegisterTenpayV3(senparcWeixinSetting, "XXX公衆號");
            //記錄到同一個 SenparcWeixinSettingItem 對象中

Global

此處修改完成後我們就可以動手開始寫controller了
paycontroller

支付代碼如下:

using Senparc.Weixin.Helpers;
using Senparc.Weixin.TenPay;
using Senparc.Weixin.TenPay.V3;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.Mvc;

namespace TestPay.Controllers
{
    public class WeiXinController : Controller
    {
        private static TenPayV3Info _tenPayV3Info;
        public static TenPayV3Info TenPayV3Info
        {
            get
            {
                if (_tenPayV3Info == null)
                {

                    var key = TenPayHelper.GetRegisterKey(Senparc.Weixin.Config.SenparcWeixinSetting);
                    _tenPayV3Info =
                        TenPayV3InfoCollection.Data[key];
                }
                return _tenPayV3Info;
            }
        }

        // GET: WeiXin
        public ActionResult H5Pay()
        {

            string total_amout = null;//支付價格
            string Guid = GetSerialNumber();//系統內訂單號我這裏是生成的時間+隨機數字//注意不要超過32位否則微信會報錯

            // 商品描述
            string body = "測試支付";
            string openId = "";
            var timeStamp = TenPayV3Util.GetTimestamp();//時間戳
            var nonceStr = TenPayV3Util.GetNoncestr();

            var price = total_amout == null ? 1 : int.Parse(total_amout) * 100;//注意微信支付單位爲分所以要100  如果傳1就是1分錢 傳100就是1塊錢
            //var ip = Request.Params["REMOTE_ADDR"];
            var xmlDataInfo = new TenPayV3UnifiedorderRequestData(TenPayV3Info.AppId, TenPayV3Info.MchId, body, Guid, price, Request.UserHostAddress, TenPayV3Info.TenPayV3Notify, TenPayV3Type.MWEB/*此處無論傳什麼,方法內部都會強制變爲MWEB*/, openId, TenPayV3Info.Key, nonceStr);

            var result = TenPayV3.Html5Order(xmlDataInfo);//調用統一訂單接口
                                                          //JsSdkUiPackage jsPackage = new JsSdkUiPackage(TenPayV3Info.AppId, timeStamp, nonceStr,);
            var package = string.Format("prepay_id={0}", result.prepay_id);//預支付訂單id

            string paysign = TenPayV3.GetJsPaySign(TenPayV3Info.AppId, timeStamp, nonceStr, package, TenPayV3Info.Key);//簽名sign

            //設置成功頁面(也可以不設置,支付成功後默認返回來源地址)
            string returnUrl = "";


            string hosturl = Request.Url.Host;

            returnUrl =hosturl+ "/WeiXin/PayOK";//支付成功後跳轉網址



            var mwebUrl = result.mweb_url;
            if (!string.IsNullOrEmpty(returnUrl))
            {
                mwebUrl += string.Format("&redirect_url={0}", AsUrlData(returnUrl));
            }
            return Json(new { id = 1, result = mwebUrl });
        }


        #region  url處理
        public static string AsUrlData(string data)
        {
            if (data == null)
            {
                return null;
            }
            return Uri.EscapeDataString(data);
        }

        #endregion


        #region  生成隨機流水或

        private static long np1 = 0, np2 = 0, np3 = 1; //臨時計算用。
        private static object orderFormNumberLock = new object();//線程並行鎖,以保證同一時間點只有一個用戶能夠操作流水號。如果分多個流水號段,放多個鎖,並行壓力可以更好的解決,大家自己想法子擴充吧
        private string strOrderNumber = null;//訂單號。
        /// <summary>
        /// 生成充值流水號格式:8位日期加8位順序號,如2010030200000056。
        /// </summary>
        public string GetSerialNumber()
        {
      
            DateTime now = DateTime.Now;
            TimeSpan span = now - DateTime.MinValue;
            long tmpDays = span.Days;
            long seconds = span.Hours * 3600 + span.Seconds;
            StringBuilder sb = new StringBuilder();
            Monitor.Enter(orderFormNumberLock); //鎖定資源
            if (tmpDays != np1)
            {
                np1 = tmpDays;
                np2 = 0;
                np3 = 1;
            }
            if (np2 != seconds)
            {
                np2 = seconds;
                np3 = 1;
            }
            sb.Append(Convert.ToString(np1, 16).PadLeft(5, '0') + Convert.ToString(np2, 16).PadLeft(5, '0') + Convert.ToString(np3++, 16).PadLeft(6, '0'));
            Monitor.Exit(orderFormNumberLock); //釋放資源
            strOrderNumber = sb.ToString();
            return strOrderNumber;
        }
        #endregion
    }

}

完成後我們選擇微信支付如下圖所示吊起微信
微信支付

完成微信支付後我們開始支付寶的開發

同樣支付寶支付我們需要一個AliPay.AopSDK的dll
AliPay.AopSDK

我們再次將配置需要的參數寫入web.config中

    <!--應用ID,您的APPID-->
    <add key="app_id" value="xxxxxxxxx" />
    <add key="gatewayUrl" value="https://openapi.alipay.com/gateway.do" />
    <!--商戶私鑰,您的原始格式RSA私鑰-->
    <add key="private_key" value="xxxxxxx" />
    <!--支付寶公鑰,查看地址:https://openhome.alipay.com/platform/keyManage.htm 對應APPID下的支付寶公鑰。-->
    <add key="alipay_public_key" value="xxxxxxx" />
    <add key="sign_type" value="RSA2" />
    <add key="charset" value="UTF-8" />

controller 如下所示

using Aop.Api;
using Aop.Api.Domain;
using Aop.Api.Request;
using Aop.Api.Response;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace TestPay.Controllers
{
    public class AliPayController : Controller
    {
        // GET: AliPay

        [HttpPost]
        public void ALiPay()
        {

            string gatewayUrl = ConfigurationManager.AppSettings["gatewayUrl"].ToString();
            string app_id = ConfigurationManager.AppSettings["app_id"].ToString();
            string private_key = ConfigurationManager.AppSettings["private_key"].ToString();
            string sign_type = ConfigurationManager.AppSettings["sign_type"].ToString();
            string alipay_public_key = ConfigurationManager.AppSettings["alipay_public_key"].ToString();
            string charset = ConfigurationManager.AppSettings["charset"].ToString();

            DefaultAopClient client = new DefaultAopClient(gatewayUrl, app_id,private_key, "json", "1.0", sign_type, alipay_public_key, charset, false);

            string hosturl = Request.Url.Host;


            // 外部訂單號,商戶網站訂單系統中唯一的訂單號
            string out_trade_no = Helper.GetSerialNumber();//系統內訂單號我這裏是生成的時間+隨機數字//注意不要超過64位否則微信會報錯

            // 訂單名稱
            string subject = "測試支付";


            // 付款金額
            string total_amout = "0.01";

            //string total_amout = "0.01";


            // 商品描述
            string body = "測試支付";
            string quit_url = "";


            // 支付中途退出返回商戶網站地址
            quit_url = hosturl + "H5pay/Index";


            // 組裝業務參數model
            AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
            model.Body = body;
            model.Subject = subject;
            model.TotalAmount = total_amout;
            model.OutTradeNo = out_trade_no;
            model.ProductCode = "QUICK_WAP_WAY";
            model.QuitUrl = quit_url;

            AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();


            // 設置支付完成同步回調地址
            request.SetReturnUrl(hosturl + "H5pay/PayOK");
            // 設置支付完成異步通知接收地址
            request.SetNotifyUrl(hosturl + "H5pay/Notify_url");



            // 將業務model載入到request
            request.SetBizModel(model);

            AlipayTradeWapPayResponse response = null;
            try
            {
                response = client.pageExecute(request, null, "post");
                Response.Write(response.Body);

            }
            catch (Exception exp)
            {

                throw exp;

            }
        }
    }
}

完成後代碼效果如下
支付寶
支付寶2

寫完支付後其實還有一步重要的步驟就是支付回調

微信支付回調

#region 微信回調方法
        [HttpPost]
        public ActionResult PayNotifyUrl()
        {

            try
            {
                ResponseHandler resHandler = new ResponseHandler(null);

                string return_code = resHandler.GetParameter("return_code");//支付結果
                string return_msg = resHandler.GetParameter("return_msg");//支付消息




                bool paySuccess = false;

                resHandler.SetKey(TenPayV3Info.Key);
                //驗證請求是否從微信發過來(安全)
                if (resHandler.IsTenpaySign() && return_code.ToUpper() == "SUCCESS")
                {
                    paySuccess = true;//正確的訂單處理
                    //直到這裏,才能認爲交易真正成功了,可以進行數據庫操作,但是別忘了返回規定格式的消息!
                }
                else
                {
                    paySuccess = false;//錯誤的訂單處理
                }

                if (paySuccess)
                {
                    /* 這裏可以進行訂單處理的邏輯 */

                    //發送支付成功的模板消息
                    try
                    {
                        string appId = Senparc.Weixin.Config.SenparcWeixinSetting.WeixinAppId;//與微信公衆賬號後臺的AppId設置保持一致,區分大小寫。
                        int total_fee = int.Parse(resHandler.GetParameter("total_fee"));//訂單金額
                        string out_trade_no = resHandler.GetParameter("out_trade_no");//商戶訂單號
                        string transaction_id = resHandler.GetParameter("transaction_id");//商戶訂單號


                      
                        //在此處編寫支付成功的邏輯



                    }
                    catch (Exception ex)
                    {
                       
                    }

                }

                string xml = string.Format(@"<xml>
<return_code><![CDATA[{0}]]></return_code>
<return_msg><![CDATA[{1}]]></return_msg>
</xml>", return_code, return_msg);
                return Content(xml, "text/xml");
            }
            catch (Exception ex)
            {
              
                throw;
            }


        }

        #endregion

支付寶支付回調

  #region 支付寶回調方法
        [HttpPost]
        public ActionResult Notify_url()
        {
            /* 實際驗證過程建議商戶添加以下校驗。
                    1、商戶需要驗證該通知數據中的out_trade_no是否爲商戶系統中創建的訂單號,
                    2、判斷total_amount是否確實爲該訂單的實際金額(即商戶訂單創建時的金額),
                    3、校驗通知中的seller_id(或者seller_email) 是否爲out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email)
                    4、驗證app_id是否爲該商戶本身。
                    */
            Dictionary<string, string> sArray = GetRequestPost();
            string gatewayUrl = ConfigurationManager.AppSettings["gatewayUrl"].ToString();
            string app_id = ConfigurationManager.AppSettings["app_id"].ToString();
            string private_key = ConfigurationManager.AppSettings["private_key"].ToString();
            string sign_type = ConfigurationManager.AppSettings["sign_type"].ToString();
            string alipay_public_key = ConfigurationManager.AppSettings["alipay_public_key"].ToString();
            string charset = ConfigurationManager.AppSettings["charset"].ToString();

            if (sArray.Count != 0)
            {
                bool flag = AlipaySignature.RSACheckV1(sArray, alipay_public_key,charset, sign_type, false);
                if (flag)
                {
                    //交易狀態
                    //判斷該筆訂單是否在商戶網站中已經做過處理
                    //如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序
                    //請務必判斷請求時的total_amount與通知時獲取的total_fee爲一致的
                    //如果有做過處理,不執行商戶的業務程序

                    //注意:
                    //退款日期超過可退款期限後(如三個月可退款),支付寶系統發送該交易狀態通知
                    string trade_status = Request.Form["trade_status"];

                    //商戶訂單號
                    string out_trade_no = Request.Form["out_trade_no"];


                    //支付寶交易號
                    string trade_no = Request.Form["trade_no"];



                    string total_amount = Request.Form["total_amount"];


                    if (trade_status == "TRADE_FINISHED" || trade_status == "TRADE_SUCCESS")
                    {

                        
                        try
                        {
                           //在此處編寫你的支付成功的邏輯
                           return Json("success");
                           
                        }
                        catch (Exception e)
                        {
                            return Json("fail");
                        }

                    }
                    else if (trade_status == "TRADE_CLOSED")
                    {
                        return Json("fail");

                    }
                    return Json("success");
                }
                else
                {

                    return Json("fail");

                }
            }
            return Json("fail");
        }


        public Dictionary<string, string> GetRequestPost()
        {
            int i = 0;
            Dictionary<string, string> sArray = new Dictionary<string, string>();
            NameValueCollection coll;
            //coll = Request.Form;
            coll = Request.Form;
            String[] requestItem = coll.AllKeys;
            for (i = 0; i < requestItem.Length; i++)
            {
                sArray.Add(requestItem[i], Request.Form[requestItem[i]]);
            }
            return sArray;

        }

      #endregion


需要源碼的請
在這裏插入圖片描述
回覆 H5源碼
獲得下載地址

如果有使用地方不懂的可以添加博主QQ:864015769進行諮詢,添加時備註來意(如H5支付諮詢)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章