研究了很多demo示例,最后整理出了如下的.net MVC版本的微信支付服务端代码,亲测可行,服务端所需要的其他类文件我已经打包存附件了,需要的可以下载使用
以下只实现了基础功能,如果有什么问题还请大神们多多指教。
服务端代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WeddingCarService.Models;
using Newtonsoft.Json;
using System.Text;
using System.Xml;
using System.Collections;
using System.Text.RegularExpressions;
using System.Reflection;
using WxPayAPI;
using WeddingCarService.WXPay;
namespace WeddingCarService.Controllers
{
public class Wx_Pay_Model
{
public int retcode { get; set; }
public string retmsg { get; set; }
public string appid { get; set; }
public string noncestr { get; set; }
public string package { get; set; }
public string partnerid { get; set; }
public string prepayid { get; set; }
public string timestamp { get; set; }
public string sign { get; set; }
}
public class wxPayController : Controller
{
public static string mchid = "11111"; //mchid
public static string appId = "11111"; //appid
public static string appsecret = "11111"; //appsecret
public static string appkey = "11111"; //paysignkey(非appkey 在微信商户平台设置 (md5)111111111111)
public static string notify_url = Common.CommonDefine.ServerPath + "/wxpay/wxtNotify"; //支付完成后的回调处理页面
//
// GET: /wxPay/
public ActionResult Index()
{
return View();
}
/// <summary>
/// 微信支付主体接口
/// </summary>
/// <returns></returns>
public ActionResult wxpay()
{
//************************************************支付参数接收********************************
///获取金额
string amount = Request.QueryString["_amount"];
string sp_billno = string.IsNullOrEmpty(Request.QueryString["_orderid"]) ? DateTime.Now.ToString("yyyyMMddhhmmssffff") : Request.QueryString["_orderid"];
string detail = Request.QueryString["_detail"];
double dubamount;
double.TryParse(amount, out dubamount);
//根据appid和appappsecret获取refresh_token
//string url_token = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", appId, appsecret);
//string returnStr = tokenservice.GetToken(appId, appsecret);
//时间戳
var timeStamp = TenpayUtil.getTimestamp();
//随机验证码
var nonceStr = TenpayUtil.getNoncestr();
//****************************************************************获取预支付订单编号***********************
//设置package订单参数
Hashtable packageParameter = new Hashtable();
packageParameter.Add("appid", appId);//开放账号ID
packageParameter.Add("mch_id", mchid); //商户号
packageParameter.Add("nonce_str", nonceStr); //随机字符串
packageParameter.Add("body", detail); //商品描述
packageParameter.Add("out_trade_no", sp_billno); //商家订单号
packageParameter.Add("total_fee", (dubamount*100).ToString()); //商品金额,以分为单位
packageParameter.Add("spbill_create_ip", Request.UserHostAddress); //订单生成的机器IP,指用户浏览器端IP
packageParameter.Add("notify_url", notify_url); //接收财付通通知的URL
packageParameter.Add("trade_type", "APP");//交易类型
packageParameter.Add("fee_type", "CNY"); //币种,1人民币 66
//获取签名
var sign = CreateMd5Sign("key", appkey, packageParameter, Request.ContentEncoding.BodyName);
//拼接上签名
packageParameter.Add("sign", sign);
//生成加密包的XML格式字符串
string data = parseXML(packageParameter);
//调用统一下单接口,获取预支付订单号码
string prepayXml = HttpUtil.Send(data, "https://api.mch.weixin.qq.com/pay/unifiedorder");
//获取预支付ID
var prepayId = string.Empty;
var xdoc = new XmlDocument();
xdoc.LoadXml(prepayXml);
XmlNode xn = xdoc.SelectSingleNode("xml");
XmlNodeList xnl = xn.ChildNodes;
if (xnl.Count > 7)
{
prepayId = xnl[7].InnerText;
}
//**************************************************封装调起微信客户端支付界面字符串********************
//设置待加密支付参数并加密
Hashtable paySignReqHandler = new Hashtable();
paySignReqHandler.Add("appid", appId);
paySignReqHandler.Add("partnerid", mchid);
paySignReqHandler.Add("prepayid", prepayId);
paySignReqHandler.Add("package", "Sign=WXPay");
paySignReqHandler.Add("noncestr", nonceStr);
paySignReqHandler.Add("timestamp", timeStamp);
var paySign = CreateMd5Sign("key", appkey, paySignReqHandler, Request.ContentEncoding.BodyName);
//设置支付包参数
Wx_Pay_Model wxpaymodel = new Wx_Pay_Model();
wxpaymodel.retcode = 0;//5+固定调起参数
wxpaymodel.retmsg = "ok";//5+固定调起参数
wxpaymodel.appid = appId;//AppId,微信开放平台新建应用时产生
wxpaymodel.partnerid = mchid;//商户编号,微信开放平台申请微信支付时产生
wxpaymodel.prepayid = prepayId;//由上面获取预支付流程获取
wxpaymodel.package = "Sign=WXpay";//APP支付固定设置参数
wxpaymodel.noncestr = nonceStr;//随机字符串,
wxpaymodel.timestamp = timeStamp;//时间戳
wxpaymodel.sign = paySign;//上面关键参数加密获得
//将参数对象直接返回给客户端
return Json(new { msg = "", result = wxpaymodel }, JsonRequestBehavior.AllowGet);
}
/// <summary>
/// 将类对象拼接成调起支付字符串
/// </summary>
/// <param name="_model"></param>
/// <returns></returns>
private string ReSetPayString(Wx_Pay_Model _model)
{
StringBuilder strpay = new StringBuilder();
PropertyInfo[] props = _model.GetType().GetProperties();
strpay.Append("{");
foreach (PropertyInfo property in props)
{
strpay.Append(property.Name + ":\""+property.GetValue(_model, null).ToString()+"\",");
}
strpay.Remove(strpay.Length - 1, 1);
strpay.Append("}");
return strpay.ToString();
}
/// <summary>
/// 输出XML
/// </summary>
/// <returns></returns>
public string parseXML(Hashtable _parameters)
{
var sb = new StringBuilder();
sb.Append("<xml>");
var akeys = new ArrayList(_parameters.Keys);
foreach (string k in akeys)
{
var v = (string)_parameters[k];
if (Regex.IsMatch(v, @"^[0-9.]$"))
{
sb.Append("<" + k + ">" + v + "</" + k + ">");
}
else
{
sb.Append("<" + k + "><![CDATA[" + v + "]]></" + k + ">");
}
}
sb.Append("</xml>");
return sb.ToString();
}
/// <summary>
/// 创建package签名
/// </summary>
/// <param name="key">密钥键</param>
/// <param name="value">财付通商户密钥(自定义32位密钥)</param>
/// <returns></returns>
public virtual string CreateMd5Sign(string key, string value, Hashtable parameters, string _ContentEncoding)
{
var sb = new StringBuilder();
//数组化键值对,并排序
var akeys = new ArrayList(parameters.Keys);
akeys.Sort();
//循环拼接包参数
foreach (string k in akeys)
{
var v = (string)parameters[k];
if (null != v && "".CompareTo(v) != 0
&& "sign".CompareTo(k) != 0 && "key".CompareTo(k) != 0)
{
sb.Append(k + "=" + v + "&");
}
}
//最后拼接商户自定义密钥
sb.Append(key + "=" + value);
//加密
string sign = MD5Util.GetMD5(sb.ToString(), _ContentEncoding).ToUpper();
//返回密文
return sign;
}
/// <summary>
/// 日志记录工具类
/// </summary>
/// <param name="pathWrite"></param>
/// <param name="content"></param>
public static void WriteFile(string pathWrite, string content)
{
try
{
if (System.IO.File.Exists(pathWrite))
{
//System.IO.File.Delete(pathWrite);
}
else
{
System.IO.File.Create(pathWrite);
}
System.IO.File.AppendAllText(pathWrite, content + "\r\n----------------------------------------\r\n",
Encoding.GetEncoding("utf-8"));
}
catch (Exception e)
{
}
}
/// <summary>
/// 微信支付异步回调方法
/// </summary>
/// <returns></returns>
public ActionResult wxtNotify()
{
ResultNotify resultNotify = new ResultNotify(Request);
resultNotify.ProcessNotify();
return Json(new { msg = "成功" }, JsonRequestBehavior.AllowGet);
}
}
}
客户端代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title></title>
<script src="js/mui.min.js"></script>
<link href="css/mui.min.css" rel="stylesheet" />
<script type="text/javascript" charset="utf-8">
mui.init();
var channel = null;
var channels = null;
// 1. 获取支付通道
function plusReady() {
// 获取支付通道
plus.payment.getChannels(function(cs) {
channels = cs;
}, function(e) {
alert("获取支付通道失败:" + e.message);
});
}
document.addEventListener('plusready', plusReady, false);
var ALIPAYSERVER = 'http://demo.dcloud.net.cn/helloh5/payment/alipay.php?total=';
var WXPAYSERVER = 'http://192.168.3.141/wxPay/wxpay';
/*var WXPAYSERVER = 'http://demo.dcloud.net.cn/payment/?payid=wxpay&appid=HBuilder&total=1';*/
// 2. 发起支付请求
function pay(id) {
// 从服务器请求支付订单
var PAYSERVER = '';
if (id == 'alipay') {
PAYSERVER = ALIPAYSERVER;
} else if (id == 'wxpay') {
PAYSERVER = WXPAYSERVER;
} else {
plus.nativeUI.alert("不支持此支付通道!", null, "捐赠");
return;
}
//获取支付通道
for (var i in channels) {
if (channels[i].id == id) {
channel = channels[i];
}
}
mui.get(PAYSERVER, {
_amount: 1,
_orderid: "",
_detail: "测试微信支付"
}, function(data) {
var varpay = {
retcode: 0,
retmsg: "ok",
appid: data.result.appid,
noncestr: data.result.noncestr,
package: "Sign=WXPay",
partnerid: data.result.partnerid,
prepayid: data.result.prepayid,
timestamp: data.result.timestamp,
sign: data.result.sign
}
plus.payment.request(channel, varpay, function(result) {
plus.nativeUI.alert("支付成功!", function() {
back();
});
}, function(e) {
plus.nativeUI.alert("支付失败:" + e.code + "支付失败:" + e.message);
console.log(e.code);
console.log(e.message);
});
}, "json");
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
switch (xhr.readyState) {
case 4:
if (xhr.status == 200) {
alert(xhr.result);
plus.payment.request(channel, xhr.result, function(result) {
plus.nativeUI.alert("支付成功!", function() {
back();
});
}, function(error) {
plus.nativeUI.alert("支付失败:" + error.code);
});
} else {
alert("获取订单信息失败!");
}
break;
default:
break;
}
}
/* xhr.open('GET',PAYSERVER);
xhr.send();*/
}
</script>
</head>
<body>
<header class="mui-bar mui-bar-nav">
<a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
<h1 class="mui-title">支付测试</h1>
</header>
<div class="mui-content">
<input type="button" class="btn btn-lg" id="pay" value="pay" onclick="pay('wxpay')" />
</div>
</body>
</html>