**C#微信支付**
要获取相关的JS-SDK的相关接口参数,我们需要先生成JSAPI-Ticket凭证,生成这个凭证代码接口实现如下所示。一般来说,这个接口的数据需要缓存起来的,具体可以自己实现处理。
///
/// 获取JSAPI_TICKET接口
///
/// 调用接口凭证
///
public string GetJSAPI_Ticket(string accessToken)
{
var url = string.Format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi", accessToken);
var result = JsonHelper<GetTicketResult>.ConvertJson(url);
return result != null ? result.ticket : null;
}
我们要实现JSSDK签名的处理,必须先根据几个变量,构建好URL字符串,具体的处理过程,我们可以把它们逐一放在一个Hashtable里面,如下代码所示
///
/// 获取JSSDK所需要的参数信息,返回Hashtable结合
///
/// 微信AppID
/// 根据Token获取到的JSSDK ticket
/// 页面URL
///
public static Hashtable GetParameters(string appId, string jsTicket, string url)
{
string timestamp = GetTimeStamp();
string nonceStr = GetNonceStr();
// 这里参数的顺序要按照 key 值 ASCII 码升序排序
string rawstring = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + url + "";
string signature = GetSignature(rawstring);
Hashtable signPackage = new Hashtable();
signPackage.Add("appid", appId);
signPackage.Add("noncestr", nonceStr);
signPackage.Add("timestamp", timestamp);
signPackage.Add("url", url);
signPackage.Add("signature", signature);
signPackage.Add("jsapi_ticket", jsTicket);
signPackage.Add("rawstring", rawstring);
return signPackage;
}
这样把它们放在哈希表里面,方便我们提取出来使用
```wx.config({
debug: false,
appId: appid, // 必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: noncestr, // 必填,生成签名的随机串
signature: signature, // 必填,签名,见附录1
jsApiList: [
'checkJsApi',
'chooseWXPay',
'hideOptionMenu'
]
});
## 为了在MVC视图页面里面,设置我们计算出来的值,一般我们需要在后台进行计算好,并把它们放在ViewBag变量中就可以在页面前端使用了,如下所示是MVC视图页面的后台代码。
///
/// 刷新JS-SDK的票据
///
protected virtual void RefreshTicket(AccountInfo accountInfo)
{
Hashtable ht = baseApi.GetJSAPI_Parameters(accountInfo.AppID, accountInfo.AppSecret, Request.Url.AbsoluteUri);
ViewBag.appid = ht["appid"].ToString();
ViewBag.nonceStr = ht["noncestr"].ToString();
ViewBag.timestamp = ht["timestamp"].ToString();
ViewBag.signature = ht["signature"].ToString();
}
这样,在MVC的视图页面里面,我们的代码可以这样实现JSAPI变量的初始化。
<script language="javascript">
var openid = '@ViewBag.openid';
var appid = '@ViewBag.appid';
var noncestr = '@ViewBag.noncestr';
var signature = '@ViewBag.signature';
var timestamp = '@ViewBag.timestamp';
wx.config({
debug: false,
appId: appid, // 必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: noncestr, // 必填,生成签名的随机串
signature: signature, // 必填,签名,见附录1
jsApiList: [
'checkJsApi',
'chooseWXPay',
'hideOptionMenu'
]
});
## 3、微信支付JSAPI发起微信支付的参数处理 在第一小节里面,我提到了,初始化JS-API后,还需要使用wx.chooseWXPay发起微信支付,这个接口也有几个相关的参数。
wx.chooseWXPay({
timestamp: 0, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: '', // 支付签名随机串,不长于 32 位
package: '', // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
signType: '', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: '', // 支付签名
success: function (res) {
// 支付成功后的回调函数
}
});
## 其中这里的timestamp和nonceStr的规则和前面初始化操作的参数规则一样,但是注意不能和初始化接口的timestamp和nonceStr保持一样,否则发起支付会出现【 支付验证签名失败】的错误。 package的变量就是我们调用统一下单接口的获得的预下单id,格式如下所示: prepay_id=wx2016051517463160322779de0375788970 而为了获得这个预下单的ID,我们先需要根据统一下单接口的需要,构建一个数据对象,如下所示。
PayOrderData data = new PayOrderData()
{
product_id = id,
body = "测试支付" + id,
attach = "爱奇迪技术支持",
detail = "测试JSAPI支付" + id,
total_fee = 1,
goods_tag = "test" + id,
trade_type = "JSAPI",
openid = openid
};
然后调用前面封装过的统一下单接口API获取对应的统一下单ID
TenPayApi api = new TenPayApi(accountInfo);
var orderResult = api.UnifiedOrder(data);
LogHelper.Debug(string.Format("统一下单结果:{0}", (orderResult != null) ? orderResult.ToJson() : "为空值"));
if (string.IsNullOrEmpty(orderResult.prepay_id) || string.IsNullOrEmpty(orderResult.appid))
{
throw new WeixinException("统一下单结果返回失败!");
}
signType固定为MD5,
最后剩下paySign这个比较复杂的参数了,这个参数就是需要根据前面这些参数进行签名的值。微信支付的签名还是和普通API的做法(在前面介绍微信支付的时候,有介绍过相关的规则,具体可以看看《C#开发微信门户及应用(32)--微信支付接入和API封装使用》),引入实体类 WxPayData 来存储一些业务参数,以及实现参数的签名处理。
值得注意的是,使用普通API的签名为Sign,而使用JSAPI的签名变量名称为paySign,两者处理逻辑一样,只是名称不同。
这样我们在后台处理相关的变量的代码如下所示。
///
/// 获取JSAPI方式的微信字符串参数对象
///
/// 当前账号
/// 统一下单ID
///
private WxPayData GetJSPayParam(AccountInfo accountInfo, string prepay_id)
{
WxPayData data = new WxPayData();
data.SetValue("appId", ViewBag.appId);
data.SetValue("timeStamp", data.GenerateTimeStamp());
data.SetValue("nonceStr", data.GenerateNonceStr());
data.SetValue("signType", "MD5");
data.SetValue("package", string.Format("prepay_id={0}", prepay_id));
data.SetValue("paySign", data.MakeSign(accountInfo.PayAPIKey));//签名
return data;
}
## 然后,再定义一个控制器接口,返回相关的参数数据,部分逻辑代码如下所示。这样方便前端通过JSON的格式获取对应的变量值
//支付需要的参数
WxPayData param = GetJSPayParam(accountInfo, orderResult.prepay_id);
LogHelper.Debug("GetJSPayParam:" + param.ToJson());
var obj = new
{
timeStamp = param.GetString("timeStamp"),
nonceStr = param.GetString("nonceStr"),
signType = param.GetString("signType"),
package = param.GetString("package"),
paySign = param.GetString("paySign")
};
return Content(obj.ToJson());
## 在前面页面,通过ajax方式获得发起微信支付的相关参数,代码如下所示。
//发起一个微信支付
function chooseWXPay(id) {
//alert(window.location.href);
var uid = getUrlVars()["uid"];
$.ajax({
type: 'POST',
url: '/JSSDKTest/GetWXPayData',
//async: false, //同步
dataType: 'json',
data : {
id: id,
uid: uid,
openid : openid
},
success: function (json) {
wx.chooseWXPay({
appId: appid,
timestamp: json.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: json.nonceStr, // 支付签名随机串,不长于 32 位
package: json.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
signType: json.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: json.paySign, // 支付签名
success: function (res) { // 支付成功后的回调函数
if (res.errMsg == 'chooseWXPay:ok') {
$.toast('支付成功');
//setTimeout(function () {
// window.location.href = "/";//这里默认跳转到主页
//}, 2000);
//window.location.href = "/Pay/order_details?orderId=" + $("#orderId").val();
} else if (res.errMsg == 'chooseWXPay:cancel' || res.errMsg == 'chooseWXPay:fail') {
$.toast("支付失败");
//window.location.href = "/Pay/order_details?orderId=" + $("#orderId").val();
}
},
cancel: function () {
$.toast("用户取消了支付");
//window.location.href = "/Pay/order_details?orderId=" + $("#orderId").val();
}
});
wx.error(function (res) {
$.toast("调用支付出现异常");
//window.location.href = "/Pay/order_details?orderId=" + $("#orderId").val();
})
},
error: function (xhr, status, error) {
$.toast("操作失败" + xhr.responseText); //xhr.responseText
}
});
};