C#实现微信小程序支付,也就是后台调用微信小程序支付接口完成支付从编码的角度来说有两种方式:
1.自己纯手写代码,封装参数,通过http get或post 提交参数完成调用。
2.使用第三方封装好的库,给指定参数赋值完成调用。
经常编码的同学们一定对于使用GitHub开源库乐此不疲,因为确实能够提升开发效率,避免重复造轮子。所以我们实现微信小程序支付就采用第二种方案。
需要注意的是在开始编码之前你需要一些前提准备:
1.有一个微信小程序
2.有一个备案好的域名,而且服务器要安装https证书
3.申请一个商户号并与你的小程序关联
4.设置API密钥
本文主要讲解编码实现,对于前提条件准备可以参考 https://blog.csdn.net/qq_41833259/article/details/107336526
编码开始:
1.通过nuget方式为你的程序安装
Senparc.Weixin.dll
Senparc.Weixin.TenPay.dll
以及日志记录组件Serilog
Serilog.dll
Serilog.Sinks.Console.dll
Serilog.Sinks.File.dll
2.编辑支付相关参数实体类
public class PayParameters
{
/// <summary>
/// 小程序ID
/// </summary>
public string appid { get { return "wx1f1×××××3bfea"; } }
/// <summary>
/// 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
/// </summary>
public string attach { get { return "支付测试"; } }
/// <summary>
/// 商户号
/// </summary>
public string mchid { get { return "160×××××24"; } }
/// <summary>
/// 随机字符串,长度要求在32位以内。推荐随机数生成算法
/// </summary>
public string nonce { get { return Senparc.Weixin.MP.Helpers.JSSDKHelper.GetNoncestr(); } }
/// <summary>
/// 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
/// </summary>
public string notify_url { get { return "https://*****/weiXinPay/Notify"; } }
/// <summary>
/// 商品简单描述,该字段请按照规范传递,具体请见参数规定
/// </summary>
public string body { get { return "JSAPI支付测试"; } }
/// <summary>
/// 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一。详见商户订单号
/// </summary>
public string out_trade_no { get; set; }
/// <summary>
/// 支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IP
/// </summary>
public string spbill_create_ip { get { return "127.0.0.1"; } }
/// <summary>
/// 订单总金额,单位为分,详见支付金额
/// </summary>
public int total_fee { get { return 10; } }
/// <summary>
/// 小程序取值如下:JSAPI,详细说明见参数规定
/// </summary>
public string trade_type { get { return "JSAPI"; } }
/// <summary>
/// 交易过程生成签名的密钥,仅保留在商户系统和微信支付后台,
/// 不会在网络中传播。商户妥善保管该Key,切勿在网络中传输,
/// 不能在其他客户端中存储,保证key不会被泄漏。商户可根据邮件
/// 提示登录微信商户平台进行设置。也可按以下路径设置:
/// 微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
/// </summary>
public string key { get { return "ujlHIzeSU*******ZJHJmQR"; } }
/// <summary>
/// AppSecret是APPID对应的接口密码,用于获取接口调用凭证时使用
/// </summary>
public string secret { get { return "3abb32307a*******fa1da4b59"; } }
/// <summary>
/// 是否需要分账 Y-是,需要分账 N-否,不分账 字母要求大写,不传默认不分账
/// </summary>
public string profit_sharing { get; set; }
}
需要注意的是参数中有个notify_url,这个是回调接口地址,微信在支付完毕时候会主动调用此接口,返回当前支付结果
3.编写预下单函数
public PayRequesEntity PrePay(string tradeNo, string openId)
{
var paramter = new PayParameters();
//分账
paramter.profit_sharing = "Y";
paramter.out_trade_no = tradeNo;//支付订单号 自己系统单号
var timeStamp = TenPayV3Util.GetTimestamp();//时间戳
var nonceStr = TenPayV3Util.GetNoncestr();//随机字符串
var openid = openId;//用户openid
//构造提交数据
TenPayV3UnifiedorderRequestData tenPayV3 = new TenPayV3UnifiedorderRequestData(paramter.appid, paramter.mchid,
paramter.body, paramter.out_trade_no, paramter.total_fee, paramter.spbill_create_ip, paramter.notify_url,
Senparc.Weixin.TenPay.TenPayV3Type.JSAPI, openid, paramter.key, nonceStr,profitSharing:"Y");
//提交支付接口
Serilog.Log.Information("支付参数:{0}", tenPayV3.PackageRequestHandler.ParseXML());
UnifiedorderResult result = TenPayV3.Unifiedorder(tenPayV3);
Serilog.Log.Information("支付结果:{@UnifiedorderResult}", result);
PayRequesEntity payEntity = new PayRequesEntity();
if (result.return_code == "SUCCESS" && result.result_code == "SUCCESS")
{
//预下单成功
payEntity.timeStamp = timeStamp;
payEntity.nonceStr = nonceStr;
payEntity.package = "prepay_id=" + result.prepay_id;
payEntity.signType = "MD5";
payEntity.paySign = TenPayV3.GetJsPaySign(paramter.appid, timeStamp, nonceStr, payEntity.package, paramter.key);
}
else
{
//预下单失败
}
return payEntity;
}
4.微信小程序端编写
var url = app.globalData.baseUrl+"/api/services/weiXinPay/PrePay?tradeNo=000012&openId=" + app.globalData.openid;
wx.request({
url: url,
method: 'GET',
header: {
'Authorization': "Bearer " + app.globalData.token,
},
data: {
},
success: function (res) {
//调用支付窗口
console.log(res.data);
//微信拉起支付窗口
wx.requestPayment({
timeStamp: res.data.Result.timeStamp,
nonceStr: res.data.Result.nonceStr,
package: res.data.Result.package,
paySign: res.data.Result.paySign,
signType: 'MD5',
success(pay) {
console.log(pay);
//_self.payOrderNotifyHandler(data);
},
fail(res) {
console.log(res);
// uni.redirectTo({
// url: './orderFail?orderCode=' + data.orderCode
// })
},
complete(res) {
}
})
}
})
上述代码中首先调用预下单接口PrePay获取拉起支付窗口需要的参数timeStamp,nonceStr,package,paySign
然后调用微信的wx.requestPayment函数完成支付
5.回调函数
public string Notify()
{
var paramter = new PayParameters();
ResponseHandler resHandler = new ResponseHandler(HttpContext.Current);
string return_code = resHandler.GetParameter("return_code");
string return_msg = resHandler.GetParameter("return_msg");
//回到接口
Serilog.Log.Information("支付完毕回调");
Serilog.Log.Information(return_code);
Serilog.Log.Information(return_msg);
Serilog.Log.Information(resHandler.GetParameter("result_code"));
Serilog.Log.Information(resHandler.GetParameter("device_info"));
string res = null;
resHandler.SetKey("ujlHIzeS××××××JHJmQR");
//验证请求是否从微信发过来(安全)
if (resHandler.IsTenpaySign() && return_code.ToUpper() == "SUCCESS")
{
res = "success";//确的订单处理
return_msg = "OK";
Serilog.Log.Information("交易成功,可以修改订单状态");
//直到这里,才能认为交易真正成功了,可以进行数据库操作,但是别忘了返回规定格式的消息!
var appid = resHandler.GetParameter("appid");
var mch_id = resHandler.GetParameter("mch_id");
var device_info = resHandler.GetParameter("device_info");
var result_code = resHandler.GetParameter("result_code");
var openid = resHandler.GetParameter("openid");
//微信支付订单号
var transaction_id = resHandler.GetParameter("transaction_id");
var out_trade_no = resHandler.GetParameter("out_trade_no");
var time_end = resHandler.GetParameter("time_end");
Serilog.Log.Information("transaction_id {0} out_trade_no {1}", transaction_id, out_trade_no);
Serilog.Log.Information("Notify:{0} ", resHandler.ParseXML());
}
else
{
res = "wrong";
}
string xml = string.Format(@"<xml><return_code><![CDATA[{0}]]></return_code><return_msg><![CDATA[{1}]]></return_msg></xml>", return_code, return_msg);
Serilog.Log.Information("*******End********");
HttpContext.Current.Response.ContentType = "text/xml";
return xml;
}
在回调函数中确认订单支付状态,如果返回的是Success那么就是支付成功,可以修改订单状态为已支付
至此,整个C#完成微信支付就结束了。具体的流程,参数含义也请参考微信官方文档。