C# MVC 微信支付教程系列之扫码支付代码实例

今天,我们来一起探讨一下这个微信扫码支付。何为扫码支付呢?这里面,扫的码就是二维码了,就是我们经常扫一扫的那种二维码图片,例如,我们自己添加好友的时候,可以通过输入对方的微信号,也可以扫一扫对方的二维码。扫码支付,作为,微信支付里面,不可或缺的一个功能,对商品的支付提供了极为方便的体验,用途也非常的多。

例如我们在地铁、公交站常见的那些自动售货机(不错,就是那种投硬币,就可以自动出货的那种机器)中都用到。微信(支付宝)的扫码支付的出现,大大的减少了这方面的风险,近些年来,二维码的应用越来越广,甚至有些地方,直接用来自动售票(就是把起始点设定好,票价设定好,直接把二维码贴出来,让乘客自动扫相关的二维码,完成购票,上车的时候,只需要提供自己的支付凭证给乘车员验证即可),这样,不仅绿色环保了,还大大的提高了售票的速度(去过大车站购票的人应该深有体验,排队买个票,好歹半个小时以上,心里也是万头草泥马在奔腾的)。

咱就不扯远了,说回咱么今天要做的微信支付之扫码支付。微信官方的文档,这个扫码支付(NativePay)分为两种,一种是“生成扫描支付模式”,另外一种是“生成直接支付url,支付url有效期为2小时”,至于这里面,两种扫码模式,怎么灵活利用呢,官方也没有一个明确的说明。个人理解为,第一种(生成扫描支付模式),适用于固定二维码的,就是永久使用的那种。

例如一些商家的公众号的二维码,是永久的,什么时候扫,都是关注这个公众号的,但是,这种的话,我记得微信是有限量的,貌似是一个公众号,限量10w,个人观点,觉得这个限量,是足够我们使用的。第二种(生成直接支付url,支付url有效期为2小时),这种的话,因为有有效期这种时间限制,超过了2个小时,该二维码就失效,但是对生成的二维码数量没有限制,所以,这种个人观点觉得适用于那种临时根据实际情况生成的二维码,例如:公众平台登陆的时候二次验证的二维码,自定义生成,仅为一次性缴费使用的二维码,等等)。接下来,我们就开始讲讲实际例子,首先将的就是第一种模式。

扫码支付之模式一(生成扫描支付模式):

首先,我们新建一个“MVC”的项目(asp.net的官方的demo就是了,要asp.net的自己看demo吧,demo地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1),然后把系统自动生成的HomeControler和View中的Home都删了。

然后自己新建一个HomeControler,代码如下:

 // GET: Home
 public ActionResult Index()
 {
  return View();
 } 

再添加一个View,代码如下:

@{
 Layout = null;
}
<!DOCTYPE html>
<html>
<head>
 <meta name="viewport" content="width=device-width" />
 <title>首页</title>
</head>
<body>
 <div>
 </div>
</body>
</html>

接下来,我们先把官方的demo的一些我们会用到的东西拷贝过来,其中包括以下几个文件夹,如下图:

就这个lib和business两个,把这两个文件夹,支付复制到咱们的新项目中,并且包含在项目中,如下:

然后我们再“重新生成”以下项目,或者快捷键:ctrl+shift+b,这时候,会提下如下错误:

这时候,我们去添加引用,把lib文件夹中的LitJson.dll 添加上即可,如下图:

到这里,我们就基本把官方的demo的环境给搭建好了,接下来,我们就要开始编写代码了。

首先,我的逻辑是,从前到后,就是从前端到后端。前端是显示二维码的地方,那么我们就先给他一个div(本文使用到的是jquery的二维码生成插件,全名叫:jquery.qrcode.min.js,我会传到附件上),然后在页面加载完毕的时候,会请求后台,让他返回二维码字符串,然后再通过jquery的二维码生成插件,让他生成二维码并显示在前台,代码如下:

前端:

@{
 Layout = null;
}
<!DOCTYPE html>
<html>
<head>
 <meta name="viewport" content="width=device-width" />
 <title>首页</title>
 <link href="~/Scripts/jquery-easyui-1.4.5/themes/bootstrap/easyui.css" rel="stylesheet" />
 <link href="~/Scripts/jquery-easyui-1.4.5/themes/mobile.css" rel="stylesheet" />
 <link href="~/Scripts/jquery-easyui-1.4.5/themes/icon.css" rel="stylesheet" />
</head>
<body>
 <p>
  模式一:生成扫描支付模式
  <br />
  <div id="QRCode1">
  </div>
 </p>
 <p>
  模式二:生成直接支付url,支付url有效期为2小时
  <br />
  <div id="QRCode2">
  </div>
 </p>
 <script src="~/Scripts/jquery-1.10.2.js"></script>
 <script src="~/Scripts/jquery-easyui-1.4.5/jquery.easyui.min.js"></script>
 <script src="~/Scripts/jquery-easyui-1.4.5/jquery.easyui.mobile.js"></script>
 <script src="~/Scripts/jquery-easyui-1.4.5/easyloader.js"></script>
 <script src="~/Scripts/jquery.qrcode.min.js"></script>
 <script type="text/javascript">
  $(function () {
   fGetQRCode1();
  })
  function fGetQRCode1() {
   $.messager.progress({
    title: "",
    msg: "正在生成二维码:模式一,请稍后..."
   });
   $.ajax({
    type: "post",
    url: "/Home/GetQRCode1",
    data: {
     time: new Date(),
     productId:7788
    },
    success: function (json) {
     $.messager.progress('close');//记得关闭
     if (json.result) {
      $('#QRCode1').qrcode(json.str); //生成二维码
     }
     else {
      $('#QRCode1').html("二维码生成失败");
     }
    }
   })
  }
 </script>
</body>
</html>

后端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WxPayAPI;
namespace WxPay.Controllers
{
 public class HomeController : Controller
 {
  // GET: Home
  public ActionResult Index()
  {
   return View();
  }
  /// <summary>
  /// 模式一
  /// </summary>
  /// <returns></returns>
  [HttpPost]
  public ActionResult GetQRCode1()
  {
   object objResult = "";
   string strProductID = Request.Form["productId"];
   string strQRCodeStr = GetPrePayUrl(strProductID);
   if (!string.IsNullOrWhiteSpace(strProductID))
   {
    objResult = new { result = true, str = strQRCodeStr };
   }
   else
   {
    objResult = new { result = false };
   }
   return Json(objResult);
  }
  /**
  * 生成扫描支付模式一URL
  * @param productId 商品ID
  * @return 模式一URL
  */
  public string GetPrePayUrl(string productId)
  {
   WxPayData data = new WxPayData();
   data.SetValue("appid", WxPayConfig.APPID);//公众帐号id
   data.SetValue("mch_id", WxPayConfig.MCHID);//商户号
   data.SetValue("time_stamp", WxPayApi.GenerateTimeStamp());//时间戳
   data.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//随机字符串
   data.SetValue("product_id", productId);//商品ID
   data.SetValue("sign", data.MakeSign());//签名
   string str = ToUrlParams(data.GetValues());//转换为URL串
   string url = "weixin://wxpay/bizpayurl?" + str;
   return url;
  }
  /**
  * 参数数组转换为url格式
  * @param map 参数名与参数值的映射表
  * @return URL字符串
  */
  private string ToUrlParams(SortedDictionary<string, object> map)
  {
   string buff = "";
   foreach (KeyValuePair<string, object> pair in map)
   {
    buff += pair.Key + "=" + pair.Value + "&";
   }
   buff = buff.Trim('&');
   return buff;
  }
 }
}

这时候,模式一是不是感觉就完成了?那么我们现在试试,我们浏览该页面,如下:

然后用微信扫一扫功能扫一下,发现提示如下:

这是什么鬼,是不是,你心里面是不是想知道为啥,那我来告诉你,这是为啥,这是因为,你还没有设置回调页面或者回调页面有问题,这个时候,我们再新建一个Control,命名为:NativeNotifyController.cs,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using WxPayAPI;
namespace WxPay.Controllers
{
 public class NativeNotifyController : Controller
 {
  // GET: NativeNotify
  public ActionResult Index()
  {
   string strData = ProcessNotify();
   Response.Write(strData);
   return View();
  }
  public string ProcessNotify()
  {
   WxPayData notifyData = GetNotifyData();
   //检查openid和product_id是否返回
   if (!notifyData.IsSet("openid") || !notifyData.IsSet("product_id"))
   {
    WxPayData res = new WxPayData();
    res.SetValue("return_code", "FAIL");
    res.SetValue("return_msg", "回调数据异常");
    return res.ToXml();
   }
   //调统一下单接口,获得下单结果
   string openid = notifyData.GetValue("openid").ToString();
   string product_id = notifyData.GetValue("product_id").ToString();
   WxPayData unifiedOrderResult = new WxPayData();
   try
   {
    unifiedOrderResult = UnifiedOrder(openid, product_id);
   }
   catch (Exception ex)//若在调统一下单接口时抛异常,立即返回结果给微信支付后台
   {
    WxPayData res = new WxPayData();
    res.SetValue("return_code", "FAIL");
    res.SetValue("return_msg", "统一下单失败");
    return res.ToXml();
   }
   //若下单失败,则立即返回结果给微信支付后台
   if (!unifiedOrderResult.IsSet("appid") || !unifiedOrderResult.IsSet("mch_id") || !unifiedOrderResult.IsSet("prepay_id"))
   {
    WxPayData res = new WxPayData();
    res.SetValue("return_code", "FAIL");
    res.SetValue("return_msg", "统一下单失败");
    return res.ToXml();
   }
   //统一下单成功,则返回成功结果给微信支付后台
   WxPayData data = new WxPayData();
   data.SetValue("return_code", "SUCCESS");
   data.SetValue("return_msg", "OK");
   data.SetValue("appid", WxPayConfig.APPID);
   data.SetValue("mch_id", WxPayConfig.MCHID);
   data.SetValue("nonce_str", WxPayApi.GenerateNonceStr());
   data.SetValue("prepay_id", unifiedOrderResult.GetValue("prepay_id"));
   data.SetValue("result_code", "SUCCESS");
   data.SetValue("err_code_des", "OK");
   data.SetValue("sign", data.MakeSign());
   return data.ToXml();
  }
  /// <summary>
  /// 接收从微信支付后台发送过来的数据并验证签名
  /// </summary>
  /// <returns>微信支付后台返回的数据</returns>
  public WxPayData GetNotifyData()
  {
   //接收从微信后台POST过来的数据
   System.IO.Stream s = Request.InputStream;
   int count = 0;
   byte[] buffer = new byte[1024];
   StringBuilder builder = new StringBuilder();
   while ((count = s.Read(buffer, 0, 1024)) > 0)
   {
    builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
   }
   s.Flush();
   s.Close();
   s.Dispose();
   //转换数据格式并验证签名
   WxPayData data = new WxPayData();
   try
   {
    data.FromXml(builder.ToString());
   }
   catch (WxPayException ex)
   {
    //若签名错误,则立即返回结果给微信支付后台
    WxPayData res = new WxPayData();
    res.SetValue("return_code", "FAIL");
    res.SetValue("return_msg", ex.Message);
   }
   return data;
  }
  private WxPayData UnifiedOrder(string openId, string productId)
  {
   //统一下单
   WxPayData req = new WxPayData();
   req.SetValue("body", "广东XXXX股份有限公司");
   req.SetValue("attach", "附加信息,用于后台或者存入数据库,做自己的判断");
   req.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());
   req.SetValue("total_fee", 1);
   req.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
   req.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));
   req.SetValue("goods_tag", "商品的备忘,可以自定义");
   req.SetValue("trade_type", "NATIVE");
   req.SetValue("openid", openId);
   req.SetValue("product_id", productId);
   WxPayData result = WxPayApi.UnifiedOrder(req);
   return result;
  }
 }
}

记得,也要新建一个View,就是在Index那里,右键添加一个View,View的代码如下(你没眼花,就是空的,不管他):

@{
 Layout = null;
}
<!DOCTYPE html>
<html>
<head>
 <meta name="viewport" content="width=device-width" />
 <title>Index</title>
</head>
<body>
 <div>
 </div>
</body>
</html>

接着,把这个项目,发布出来,放到服务器的iis上,这里面,我把他发布在http://sm.lmx.ren/上面(必须要发布到网上哈,如果不懂发布的,你可以自己去学习基础知识先了),这还没完,还需要把到公众平台上,设置回调页面,操作如下:

这样,就大功告成了。这时候,我们再试试扫码,发现已经得到以下提示了,这样子,就代表,我们的模式一,已经成功完成了。如下图:

 

这时候,细心的朋友就会提问了,我这都支付成功了,怎么页面没啥提示呀,这页面不交互很不友好啊。嗯,没错,童鞋,你有前途,现在我就告诉你,怎么做交互,但是,为了你日后更加有前途,我只告诉你逻辑,具体怎么实现,自己来想,多动脑。

那么逻辑是怎么的呢?常规逻辑下,我们微信扫页面上的这个二维码的时候,这个时候,他已经把我们二维码里面的参数,传到微信服务器,然后有他们开始统一下单(如果对逻辑不清晰,可以看看官方的文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_3):他们在统一下单的时候,就会生成一个product_id,这个家伙的作用呢 ,就是告诉你现在微信服务器,已经生成了一个单号,劳资已经收到你的支付请求了,赶紧给老子付款,O(∩_∩)O哈哈~。。。停,停,停。这时候,思路不能继续往下走了。

记得,前面有个叫做“统一下单“,那既然有这个步骤,那我们可以利用一下,就是当他统一下单成功的时候,我们可以在页面更新一下状态,告诉客户:您已成功扫描,并下单成功,请支付。是不是,我们可以提示他们这个。然后等用户在手机上,支付成功的时候,这个时候,页面是不是也要反馈给用户,告诉他,小子,你的钱已经到我的口袋了,你可以走了(你走,我没有你这样的宝宝)。O(∩_∩)O哈哈~,但是,你还要停,停住,停下来。我们服务公司怎么知道这个微信用户已经付款成功了呢?来,我们把视线回到代码上,找到lib/Config.cs,如下图:

然后打开config.cs,找到以下代码:

对了,你很聪明。微信的处理逻辑就是,等用户支付成功之后,他会给这个链接发送支付结果,默认是以前那个aspx的页面,现在我换成mvc,所以,我们得手动新建一个control了,命名为:ResultNotifyController,然后代码如下:

using LmxPublic.Log;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using WxPayAPI;
namespace WxPay.Controllers
{
 public class ResultNotifyController : Controller
 {
  // GET: ResultNotify
  public ActionResult Index()
  {
   string strData = ProcessNotify();
   Response.Write(strData);
   return View();
  }
  public string ProcessNotify()
  {
   WxPayData notifyData = GetNotifyData();
   //检查支付结果中transaction_id是否存在
   if (!notifyData.IsSet("transaction_id"))
   {
    //若transaction_id不存在,则立即返回结果给微信支付后台
    WxPayData res = new WxPayData();
    res.SetValue("return_code", "FAIL");
    res.SetValue("return_msg", "支付结果中微信订单号不存在");
    return res.ToXml();
   }
   string transaction_id = notifyData.GetValue("transaction_id").ToString();
   //查询订单,判断订单真实性
   if (!QueryOrder(transaction_id))
   {
    //若订单查询失败,则立即返回结果给微信支付后台
    WxPayData res = new WxPayData();
    res.SetValue("return_code", "FAIL");
    res.SetValue("return_msg", "订单查询失败");
    return res.ToXml();
   }
   //查询订单成功
   else
   {
    WxPayData res = new WxPayData();
    res.SetValue("return_code", "SUCCESS");
    res.SetValue("return_msg", "OK");
    Log.Info(this.GetType().ToString(), "order query success : " + res.ToXml());
    string strXml = res.ToXml();
    FileLog.WriteLog(strXml);
    return res.ToXml();//如果我们走到这一步了,那就代表,用户已经支付成功了,所以,该干嘛干嘛了。
   }
  }
  /// <summary>
  /// 接收从微信支付后台发送过来的数据并验证签名
  /// </summary>
  /// <returns>微信支付后台返回的数据</returns>
  public WxPayData GetNotifyData()
  {
   //接收从微信后台POST过来的数据
   System.IO.Stream s = Request.InputStream;
   int count = 0;
   byte[] buffer = new byte[1024];
   StringBuilder builder = new StringBuilder();
   while ((count = s.Read(buffer, 0, 1024)) > 0)
   {
    builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
   }
   s.Flush();
   s.Close();
   s.Dispose();
   Log.Info(this.GetType().ToString(), "Receive data from WeChat : " + builder.ToString());
   //转换数据格式并验证签名
   WxPayData data = new WxPayData();
   try
   {
    data.FromXml(builder.ToString());
   }
   catch (WxPayException ex)
   {
    //若签名错误,则立即返回结果给微信支付后台
    WxPayData res = new WxPayData();
    res.SetValue("return_code", "FAIL");
    res.SetValue("return_msg", ex.Message);
    Log.Error(this.GetType().ToString(), "Sign check error : " + res.ToXml());
    return res;
   }

   return data;
  }
  //查询订单
  private bool QueryOrder(string transaction_id)
  {
   WxPayData req = new WxPayData();
   req.SetValue("transaction_id", transaction_id);
   WxPayData res = WxPayApi.OrderQuery(req);
   if (res.GetValue("return_code").ToString() == "SUCCESS" &&
    res.GetValue("result_code").ToString() == "SUCCESS")
   {
    return true;
   }
   else
   {
    return false;
   }
  }
 }
}

前台,对,也是要新建一个View,代码如下(没错,也是空的)

@{
 Layout = null;
}
<!DOCTYPE html>
<html>
<head>
 <meta name="viewport" content="width=device-width" />
 <title>Index</title>
</head>
<body>
 <div>
 </div>
</body>
</html>

好,模式一就到这里了,呼呼。。。没想到啊,一个模式一,让我从上午写到下午,真心累。。。还有一个模式二呢。。。喝口水先,咱,接着来。

好,喝完水,接着干,下面是模式二:

模式二(生成直接支付url,支付url有效期为2小时)

由于有了上面模式一的详细说明,模式二,我就简单一点的来说了,如果又不懂的,到群里来问我吧。

模式二,前端,增加一些代码,如下(完整的,包括模式一的代码了):

@{
 Layout = null;
}
<!DOCTYPE html>
<html>
<head>
 <meta name="viewport" content="width=device-width" />
 <title>首页</title>
 <link href="~/Scripts/jquery-easyui-1.4.5/themes/bootstrap/easyui.css" rel="stylesheet" />
 <link href="~/Scripts/jquery-easyui-1.4.5/themes/mobile.css" rel="stylesheet" />
 <link href="~/Scripts/jquery-easyui-1.4.5/themes/icon.css" rel="stylesheet" />
</head>
<body>
 <p>
  模式一:生成扫描支付模式
  <br />
  <div id="QRCode1">
  </div>
 </p>
 <p>
  模式二:生成直接支付url,支付url有效期为2小时
  <br />
  <div id="QRCode2">
  </div>
 </p>
 <script src="~/Scripts/jquery-1.10.2.js"></script>
 <script src="~/Scripts/jquery-easyui-1.4.5/jquery.easyui.min.js"></script>
 <script src="~/Scripts/jquery-easyui-1.4.5/jquery.easyui.mobile.js"></script>
 <script src="~/Scripts/jquery-easyui-1.4.5/easyloader.js"></script>
 <script src="~/Scripts/jquery.qrcode.min.js"></script>
 <script type="text/javascript">
  $(function () {
   fGetQRCode1();
  })
  function fGetQRCode1() {
   $.messager.progress({
    title: "",
    msg: "正在生成二维码:模式一,请稍后..."
   });
   $.ajax({
    type: "post",
    url: "/Home/GetQRCode1",
    data: {
     time: new Date(),
     productId:7788
    },
    success: function (json) {
     $.messager.progress('close');//记得关闭
     if (json.result) {
      $('#QRCode1').qrcode(json.str); //生成二维码
     }
     else {
      $('#QRCode1').html("二维码生成失败");
     }
     fGetQRCode2();
    },
    error: function (json) {
     $('#QRCode1').html("二维码生成失败");
     fGetQRCode2();
    }
   })
  }
  function fGetQRCode2() {
   $.messager.progress({
    title: "",
    msg: "正在生成二维码:模式二,请稍后..."
   });
   $.ajax({
    type: "post",
    url: "/Home/GetQRCode2",
    data: {
     time: new Date(),
     productId: 7788
    },
    success: function (json) {
     $.messager.progress('close');//记得关闭
     if (json.result) {
      $('#QRCode2').qrcode(json.str); //生成二维码
     }
     else {
      $('#QRCode2').html("二维码生成失败");
     }
    },
    error: function (json) {
     $('#QRCode2').html("二维码生成失败");
    }
   })
  }
 </script>
</body>
</html>

后端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WxPayAPI;
namespace WxPay.Controllers
{
 public class HomeController : Controller
 {
  // GET: Home
  public ActionResult Index()
  {
   return View();
  }
  /// <summary>
  /// 模式一
  /// </summary>
  /// <returns></returns>
  [HttpPost]
  public ActionResult GetQRCode1()
  {
   object objResult = "";
   string strProductID = Request.Form["productId"];
   string strQRCodeStr = GetPrePayUrl(strProductID);
   if (!string.IsNullOrWhiteSpace(strProductID))
   {
    objResult = new { result = true, str = strQRCodeStr };
   }
   else
   {
    objResult = new { result = false };
   }
   return Json(objResult);
  }
  /// <summary>
  /// 模式二
  /// </summary>
  /// <returns></returns>
  [HttpPost]
  public ActionResult GetQRCode2()
  {
   object objResult = "";
   string strProductID = Request.Form["productId"];
   string strQRCodeStr = GetPayUrl(strProductID);
   if (!string.IsNullOrWhiteSpace(strProductID))
   {
    objResult = new { result = true, str = strQRCodeStr };
   }
   else
   {
    objResult = new { result = false };
   }
   return Json(objResult);
  }
  /**
  * 生成扫描支付模式一URL
  * @param productId 商品ID
  * @return 模式一URL
  */
  public string GetPrePayUrl(string productId)
  {
   WxPayData data = new WxPayData();
   data.SetValue("appid", WxPayConfig.APPID);//公众帐号id
   data.SetValue("mch_id", WxPayConfig.MCHID);//商户号
   data.SetValue("time_stamp", WxPayApi.GenerateTimeStamp());//时间戳
   data.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//随机字符串
   data.SetValue("product_id", productId);//商品ID
   data.SetValue("sign", data.MakeSign());//签名
   string str = ToUrlParams(data.GetValues());//转换为URL串
   string url = "weixin://wxpay/bizpayurl?" + str;
   return url;
  }
  /**
  * 参数数组转换为url格式
  * @param map 参数名与参数值的映射表
  * @return URL字符串
  */
  private string ToUrlParams(SortedDictionary<string, object> map)
  {
   string buff = "";
   foreach (KeyValuePair<string, object> pair in map)
   {
    buff += pair.Key + "=" + pair.Value + "&";
   }
   buff = buff.Trim('&');
   return buff;
  }
  /**
  * 生成直接支付url,支付url有效期为2小时,模式二
  * @param productId 商品ID
  * @return 模式二URL
  */
  public string GetPayUrl(string productId)
  {
   WxPayData data = new WxPayData();
   data.SetValue("body", "广东XXXX股份有限公司");//商品描述
   data.SetValue("attach", "附加信息,用于后台或者存入数据库,做自己的判断");//附加数据
   data.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());//随机字符串
   data.SetValue("total_fee", 1);//总金额
   data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));//交易起始时间
   data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));//交易结束时间
   data.SetValue("goods_tag", "商品的备忘,可以自定义");//商品标记
   data.SetValue("trade_type", "NATIVE");//交易类型
   data.SetValue("product_id", productId);//商品ID
   WxPayData result = WxPayApi.UnifiedOrder(data);//调用统一下单接口
   string url = result.GetValue("code_url").ToString();//获得统一下单接口返回的二维码链接

   return url;
  }
 }
}

特此更正,感谢“ abc54288”的指出,模式二也是有回调的,回调的接口设置在Config.cs,中,如下图:

所以下面的作废,但是如果需要手动查询订单情况的,还可以用下列的方法查询。再次感谢园友:“ abc54288”。

由于模式二是没有支付结果回调的,所以,我们要查询支付成功与否,需要自己写方法来查询,官方提供的查询支付成功与否的方法有以下,

/***
  * 订单查询完整业务流程逻辑
  * @param transaction_id 微信订单号(优先使用)
  * @param out_trade_no 商户订单号
  * @return 订单查询结果(xml格式)
  */
  public static string Run(string transaction_id, string out_trade_no)
  {
   Log.Info("OrderQuery", "OrderQuery is processing...");
   WxPayData data = new WxPayData();
   if(!string.IsNullOrEmpty(transaction_id))//如果微信订单号存在,则以微信订单号为准
   {
    data.SetValue("transaction_id", transaction_id);
   }
   else//微信订单号不存在,才根据商户订单号去查单
   {
    data.SetValue("out_trade_no", out_trade_no);
   }
   WxPayData result = WxPayApi.OrderQuery(data);//提交订单查询请求给API,接收返回数据
   Log.Info("OrderQuery", "OrderQuery process complete, result : " + result.ToXml());
   return result.ToPrintStr();
  }

可以通过这个微信订单号(transaction_id)来查询,也可以通过商户订单号(out_trade_no),所以,我们要合理利用这里面的技巧,上述模式二,我用的out_trade_no 是一个随机字符串,我们可以把这个字符串记录好,放数据库还是放哪里,你自己喜欢,然后写一个ajsx长轮询来,定时查询这个商户订单号,看看有没有支付成功,来做支付确认。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C#实现微信红包功能

    本文实例为大家分享了C#仿微信红包功能的具体代码,供大家参考,具体内容如下 Program.cs代码: class Program { static void Main(string[] args) { //初始化要发起的红包基础数据 double total = 100; int num = 50; double min = 0.01; string temp; bool flag = false; Console.WriteLine(string.Format("是否需要自定义红包金额和数量

  • C# MVC 微信支付教程系列之公众号支付代码

    今天,我们接着讲微信支付的系列教程,前面,我们讲了这个微信红包和扫码支付.现在,我们讲讲这个公众号支付.公众号支付的应用环境常见的用户通过公众号,然后再通过公众号里面的菜单链接,进入公众号的商城,然后在里面完成购买和支付功能,我们可以看看官方对这个公众号支付的场景的解释,链接:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1,通过这个官方的解释,那我们大概清楚这个公众号的用途了,下面,我就说说,做这个公众号支付的准备工作有哪

  • c#版在pc端发起微信扫码支付的实例

    等了好久,微信官方终于发布了.net的demo. 主要代码: /** * 生成直接支付url,支付url有效期为2小时,模式二 * @param productId 商品ID * @return 模式二URL */ public string GetPayUrl(string productId, string body, string attach, int total_fee, string goods_tag) { Log.Info(this.GetType().ToString(), "

  • C# MVC 微信支付教程系列之扫码支付代码实例

    今天,我们来一起探讨一下这个微信扫码支付.何为扫码支付呢?这里面,扫的码就是二维码了,就是我们经常扫一扫的那种二维码图片,例如,我们自己添加好友的时候,可以通过输入对方的微信号,也可以扫一扫对方的二维码.扫码支付,作为,微信支付里面,不可或缺的一个功能,对商品的支付提供了极为方便的体验,用途也非常的多. 例如我们在地铁.公交站常见的那些自动售货机(不错,就是那种投硬币,就可以自动出货的那种机器)中都用到.微信(支付宝)的扫码支付的出现,大大的减少了这方面的风险,近些年来,二维码的应用越来越广,甚

  • ThinkPHP框架整合微信支付之Native 扫码支付模式一图文详解

    本文实例讲述了ThinkPHP框架整合微信支付之Native 扫码支付模式一.分享给大家供大家参考,具体如下: 大家好,这篇文章是继微信支付jsapi篇之后的微信支付系列教程第二篇:扫码支付之模式一介绍下扫码支付目前有两种模式,模式一比模式二稍微复杂点,至于模式一与模式二的具体内容,流程,微信开发文档都有详细介绍,这里就不多说废话,接下来赶紧上教程! 首先我们还是一样,导入微信支付的类库: 接下来是Public下的文件: 这里的配置跟JSAPI支付一样,不需要改动 具体关于文件介绍请参考JSAP

  • nodejs微信扫码支付功能实现

    前言 本篇文章主要是记录本人在微信扫码支付过程中所遇到的问题,给大家一个借鉴作用,希望对你们有帮助 开发环境 nodejs v8.1.0 egg v1.1.0 准备工作 微信公众号-appid 微信商户号-mch_id key值(签名算法所需,其实就是一个32位的密码,可以用md5生成一个)(key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置) 扫码支付-统一下单 以下才用的是微信模式二,因为比较简单 let MD5 = req

  • 微信公众平台开发教程⑤ 微信扫码支付模式介绍

    本文实例讲述了微信扫码支付模式.分享给大家供大家参考,具体如下: 背景:因为微信占据众多的用户群,作为程序开发,自然而然也成了研究的重点.毕竟个人能力有限,很难想象设计的复杂性,多数时间接触起来,各种蒙圈,在此笔记自己的操作流程,仅做参考,欢迎指正. 一.微信扫码支付模式 1.附带微信公众号"微信开发"中,对微信扫码支付的两种模式流程图以作"膜拜". 2.具体的操作,可详细参考官方开发文档 文档有强调: 模式一开发前,商户必须在公众平台后台设置支付回调URL.URL

  • ThinkPHP框架整合微信支付之Native 扫码支付模式二图文详解

    本文实例讲述了ThinkPHP框架整合微信支付之Native 扫码支付模式二.分享给大家供大家参考,具体如下: 大家好,这篇文章是继微信支付之Native 扫码支付 模式一之后的微信支付系列教程第三篇:扫码支付之模式二 介绍下扫码支付目前有两种模式,模式一比模式二稍微复杂点,至于模式一与模式二的具体内容,流程,微信开发文档都有详细介绍,这里就不多说废话,接下来赶紧上教程! 首先我们还是一样,导入微信支付的类库: 接下来是Public下的文件: 以上跟Native扫码模式一一样,不明白请看 //w

  • 微信扫码支付(PC端)

    这里的扫码支付指的是PC网站上面使用微信支付,也就是官方的模式二,网站是Asp.net MVC,整理如下.(demo在最下方) 一.准备工作 使用的微信API中的统一下单方法,关键的参数是'公众账号ID(appid)','商户号(mch_id)'和'商户支付密钥(KEY)',所以首先要有一个审核过的公众号,并开通支付功能,然后申请商户,通过审核后得到商户号,也就是商户平台的登录名.商户支付密钥是用来签名的,确保url不被篡改.进入商户平台后在API安全中设置,是一个32位的字符串. 有这三个参数

  • 分享微信扫码支付开发遇到问题及解决方案-附Ecshop微信支付插件

    最近比较工作比较轻松,帮一个朋友的基于ecshop开发的商城加入微信扫描支付功能,本以为是很简单的事儿--下载官方sdk或开发帮助文档,按着里面的做就ok了,谁知折腾了两三天的时间才算搞定,中间也带着疑问在网上找了不少技术文章,却发现都只是比较粗略的写他们是怎么开发接入的,并没有解决我遇到的问题...,唉,有时候真心的感觉'只能靠自己'. 本文就是想把自己遇到的问题及解决办法写出来,让做这方面开发的朋友有所帮助! 开发之前,先查看官方[扫码支付]开发文档,扫码支付分为以下两种模式: △模式一:

  • PHP 微信扫码支付源代码(推荐)

    代码中包含四个文件createUrl.php.ArrayToXML.php.returnGoodsUrl.php.notifyUrl.php . 具体详细代码大家可以参考下: createUrl.php:创建微信二维码支付链接 ``` /** * @author chantrans * 本页面的作用是生成商品二维码链接 */ echo createUrl("12314124"); /** * 产生随机字符串 */ function getNonceStr() $chars = 'ABC

  • PHP 接入微信扫码支付总结(总结篇)

    微信扫码支付分为两种模式, 模式一比较复杂,需要公众号配置回调地址. 模式二比较简单,只需要在代码中配置回调地址就可以了. 我这次使用的是模式二. 需要配置参数, const APPID = 'xxx'; const MCHID = 'xxx'; const KEY = 'xxx'; const APPSECRET = 'xxx'; 配置公众号的appid,appsecret.以及微信支付的mchid与key. 生成二维码,这个页面需要自己去美化,不像支付宝那样自带效果. require_onc

随机推荐