简单的实现了小程序支付,对应的api接口.
using Senparc.CO2NET.Cache;
using Senparc.CO2NET.Helpers;
using Senparc.CO2NET.Utilities;
using Senparc.Weixin;
using Senparc.Weixin.Exceptions;
using Senparc.Weixin.TenPay;
using Senparc.Weixin.TenPay.V3;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;
using System.Xml;
using System.Xml.Linq;
namespace WiseCarAPI.Controllers
{
public class wxPayController : Controller
{
public ActionResult pay(string jscode, string fee)
{
bool bosucceed = true;
try
{
string _posdata = "appid=" + appid + "&secret=" + secret + "&js_code=" + jscode + "&grant_type=authorization_code";
string _url = "https://api.weixin.qq.com/sns/jscode2session";//获取openid
string _data = request_url(_url, _posdata);
if (_data.Contains("\"openid\""))
{
string _ip = Request.ServerVariables.Get("Remote_Addr").ToString().Trim();
dynamic _modal = Newtonsoft.Json.Linq.JToken.Parse(_data) as dynamic;
string _openid = _modal.openid;
//--------以上获取openid--end,--以下获取prepay_id--begin
#region 获取prepay_id
string _nonce_str = get_nonce_str();
string timeStamp = getTimeStamp();
string _out_trade_no = DateTime.Now.ToString("yyMMddHHmmssfff" + new Random(1000).Next().ToString());// DateTime.Now.ToString("yyMMddHHmmssfff") + GetRand(1, 20).ToString();//get_nonce_str();
Dictionary<string, string> datalist = new Dictionary<string, string>();
datalist.Add("appid", appid);
datalist.Add("mch_id", mch_id);
datalist.Add("nonce_str", _nonce_str);
datalist.Add("body", "test");
//datalist.Add("detail", "{\"goods_detail\":[ { \"goods_id\":\"iphone6s_16G\", \"wxpay_goods_id\":\"1001\", \"goods_name\":\"iPhone6s 16G\", \"quantity\":1, \"price\":528800, \"goods_category\":\"123456\", \"body\":\"苹果手机\" }] }>");
datalist.Add("out_trade_no", _out_trade_no);
datalist.Add("total_fee", fee);
datalist.Add("spbill_create_ip", _ip);
datalist.Add("notify_url", notify_url);
datalist.Add("trade_type", "JSAPI");
datalist.Add("openid", _openid);
//排序datalist
string _sign = getParamSrc(datalist);//CreateMd5Sign
datalist.Add("sign", _sign);
//将datalist将成xml
string xml = getRequestXml(datalist);//ParseXML
StringBuilder str = new StringBuilder();
_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
_data = request_url(_url, xml);//获取prepay_id
#endregion
#region 解析返回的xml,求paySign
Dictionary<string, string> dirxml = (getdata_fromxml(_data));
//txt_Result.Text += "\n" + _data;
bool boGet_prepay_id = false;
string _prepay_id = "";
if (dirxml.ContainsKey("return_code"))
{
if (dirxml["return_code"].ToString().ToUpper() == "SUCCESS")
{
_prepay_id = dirxml["prepay_id"].Trim();
boGet_prepay_id = true;
}
}
if (boGet_prepay_id)
{
string _paySign = "appId=" + appid;
_paySign += "&nonceStr=" + _nonce_str;
_paySign += "&package=prepay_id=" + _prepay_id;
string _timeStamp = timeStamp;
_paySign += "&signType=MD5&timeStamp=" + _timeStamp + "&key=" + key;
string paySign = UserMd5(_paySign);
return this.Json(new { succeed = true, data = "成功", timeStamp = _timeStamp, nonceStr = _nonce_str, package = "prepay_id=" + _prepay_id, paySign = paySign, notify_url = notify_url }, JsonRequestBehavior.AllowGet);
}
else
{
return this.Json(new { succeed = false, data = "获取prepay_id失败" }, JsonRequestBehavior.AllowGet);
}
#endregion
}
else
{
return this.Json(new { succeed = false, data = "获取openid失败" }, JsonRequestBehavior.AllowGet);
}
}
catch (Exception ex)
{
return this.Json(new { succeed = false, data = ex.Message }, JsonRequestBehavior.AllowGet);
}
}
#region paytest
/// <summary>
/// 随机生成Noncestr
/// </summary>
/// <returns></returns>
public string GetNoncestr()
{
return EncryptHelper.GetMD5(Guid.NewGuid().ToString(), "UTF-8");
}
/// <summary>
/// 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名
/// </summary>
/// <param name="key">参数名</param>
/// <param name="value">参数值</param>
/// key和value通常用于填充最后一组参数
/// <returns></returns>
public string CreateMd5Sign(string key, string value, Hashtable Parameters)
{
StringBuilder sb = new StringBuilder();
ArrayList akeys = new ArrayList(Parameters.Keys);
akeys.Sort(ASCIISort.Create());
foreach (string k in akeys)
{
string v = (string)Parameters[k];
if (null != v && "".CompareTo(v) != 0
&& "sign".CompareTo(k) != 0
//&& "sign_type".CompareTo(k) != 0
&& "key".CompareTo(k) != 0)
{
sb.Append(k + "=" + v + "&");
}
}
sb.Append(key + "=" + value);
//string sign = EncryptHelper.GetMD5(sb.ToString(), GetCharset()).ToUpper();
//using Senparc.CO2NET.Helpers;
//编码强制使用UTF8:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_1
string sign = EncryptHelper.GetMD5(sb.ToString(), "UTF-8").ToUpper();
return sign;
}
/// <summary>
/// 输出XML
/// </summary>
/// <returns></returns>
public string ParseXML(Hashtable Parameters)
{
StringBuilder sb = new StringBuilder();
sb.Append("<xml>");
foreach (string k in Parameters.Keys)
{
string v = (string)Parameters[k];
if (v != null && Regex.IsMatch(v, @"^[0-9.]$"))
{
sb.Append("<" + k + ">" + v + "</" + k + ">");
}
else
{
sb.Append("<" + k + "><![CDATA[" + v + "]]></" + k + ">");
}
}
sb.Append("</xml>");
return sb.ToString();
}
#endregion
#region 回调函数
/// <summary>
/// 回调函数
/// </summary>
/// <returns></returns>
public ActionResult notifyurl()
{
try
{
Hashtable has = new Hashtable();
System.Collections.Specialized.NameValueCollection collection;
if (this.HttpContext.Request.HttpMethod.ToUpper() == "POST")
{
collection = this.HttpContext.Request.Form;
foreach (string k in collection)
{
string v = (string)collection[k];
has.Add(k, v);
}
}
collection = this.HttpContext.Request.QueryString;
foreach (string k in collection)
{
string v = (string)collection[k];
has.Add(k, v);
}
if (this.HttpContext.Request.InputStream.Length > 0)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(this.HttpContext.Request.InputStream);
XmlNode root = xmlDoc.SelectSingleNode("xml");
XmlNodeList xnl = root.ChildNodes;
foreach (XmlNode xnf in xnl)
{
has.Add(xnf.Name, xnf.InnerText);
}
}
string _xml = ParseXML(has);
Savelog(_xml);
//string temv = msg;
return this.Json(new
{
succeed = true,
data = _xml
}, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return this.Json(new
{
succeed = false,
data = ex.Message
}, JsonRequestBehavior.AllowGet);
}
}
/// <summary>
/// 保存日志文件
/// </summary>
/// <param name="saveinfo"></param>
private void Savelog(string saveinfo)
{
try
{
var logDir = Server.MapPath(string.Format("~/App_Data/TenPayNotify/{0}", SystemTime.Now.ToString("yyyyMMdd")));
if (!Directory.Exists(logDir))
{
Directory.CreateDirectory(logDir);
}
var logpath = Path.Combine(logDir, DateTime.Now.ToString("yyMMdd") + ".log");
using (var fileStream = System.IO.File.OpenWrite(logpath))
{
fileStream.Write(Encoding.Default.GetBytes(saveinfo), 0, Encoding.Default.GetByteCount(saveinfo));
fileStream.Close();
}
}
catch (Exception ex)
{
}
}
#endregion
#region 相关参数及方法
region 微信参数
string appid
{
get
{
string temV = System.Configuration.ConfigurationManager.AppSettings["appid"].Trim();
return temV;
}
}
string secret
{
get
{
string temV = System.Configuration.ConfigurationManager.AppSettings["secret"].Trim();
return temV;
}
}
string mch_id
{
get
{
string temV = System.Configuration.ConfigurationManager.AppSettings["mch_id"].Trim();
return temV;
}
}
string notify_url
{
get
{
string temV = System.Configuration.ConfigurationManager.AppSettings["notify_url"].Trim();
return temV;
}
}
string key
{
get
{
string temV = System.Configuration.ConfigurationManager.AppSettings["key"].Trim();
return temV;
}
}
#endregion
#region 获取随机字符串
/// <summary>
/// 获取随机字符串
/// </summary>
/// <returns></returns>
private string get_nonce_str()
{
string result = DateTime.Now.ToString("yyyMMddHHmmssfff");
System.Random rand = new Random();
string _strKey = "QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz";
while (result.Length < 32)
{
int _index = rand.Next(1, _strKey.Length - 1);
result += _strKey.Substring(_index, 1);
}
return result;
}
#endregion
#region 获取当前时间的时间戳
/// <summary>
/// 获取当前时间的时间戳
/// </summary>
/// <returns>时间戳的string格式</returns>
string getTimeStamp()
{
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
/// <summary>
/// 获取一定范围内的任意随机数
/// </summary>
/// <param name="minValue">最小范围</param>
/// <param name="MaxValue">最大范围</param>
/// <returns>随机数</returns>
string GetRand(int minValue, int MaxValue)
{
Random rd = new Random();
return rd.Next(minValue, MaxValue).ToString();
}
#endregion
#region 32位MD5加密
/// <summary>
/// 32位MD5加密
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public string UserMd5(string str)
{
//using System.Security;
string cl = str;
string str_md5 = "";
MD5 md5 = MD5.Create();//实例化一个md5对像
// 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择
byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
// 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得
for (int i = 0; i < s.Length; i++)
{
// 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符
str_md5 = str_md5 + s[i].ToString("x2");
}
return str_md5;
}
#endregion
#region 解析xml字符串
/// <summary>
/// 解析xml字符串
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private Dictionary<string, string> getdata_fromxml(string xml)
{
Dictionary<string, string> d_value = new Dictionary<string, string>();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
XmlNode rootNode = xmlDoc.SelectSingleNode("xml");
foreach (XmlNode xxNode in rootNode.ChildNodes)
{
string dsf = xxNode.InnerText;
string sdf = xxNode.Name;
d_value.Add(xxNode.Name, xxNode.InnerText);
}
return d_value;
}
#endregion
#region 对参数按照key=value的格式,并按照参数名ASCII字典序排序,同时求sign
/// <summary>
/// 对参数按照key=value的格式,并按照参数名ASCII字典序排序,同时求sign
/// </summary>
/// <param name="paramsMap"></param>
/// <returns></returns>
public String getParamSrc(Dictionary<string, string> paramsMap)
{
var vDic = (from objDic in paramsMap orderby objDic.Key ascending select objDic);
StringBuilder str = new StringBuilder();
foreach (KeyValuePair<string, string> kv in vDic)
{
string pkey = kv.Key;
string pvalue = kv.Value;
str.Append(pkey + "=" + pvalue + "&");
}
String result = str.ToString().Substring(0, str.ToString().Length - 1);
result += "&key=" + key;
string temV = UserMd5(result);
return temV;
}
#endregion
#region 将Dictionary转成xml
/// <summary>
/// 将Dictionary转成xml
/// </summary>
/// <param name="parameters"></param>
/// <returns></returns>
public String getRequestXml(Dictionary<string, string> parameters)
{
StringBuilder sb = new StringBuilder();
sb.Append("<xml>");
foreach (KeyValuePair<string, string> e in parameters)
{
string k = e.Key.ToString().Trim();
string v = e.Value.ToString().Trim();
if (v != null && Regex.IsMatch(v, @"^[0-9.]$"))
{
//{
sb.AppendLine("<" + k + ">" + v + "</" + k + ">");
}
else
{
sb.Append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
}
}
sb.Append("</xml>");
return sb.ToString();
}
#endregion
#region 请求api
/// <summary>
/// 请求api
/// </summary>
/// <param name="_url"></param>
/// <param name="post_data"></param>
/// <returns></returns>
private string request_url(string _url, string post_data)
{
string result = "";
// https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
string url = _url;// "https://api.weixin.qq.com/sns/jscode2session";
Encoding encoding = Encoding.UTF8;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "application/json";
//request.Headers=""
request.Method = "POST";
byte[] buffer = encoding.GetBytes(post_data.Trim());
request.ContentLength = buffer.Length;
request.GetRequestStream().Write(buffer, 0, buffer.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
{
result = reader.ReadToEnd();
}
return result;
}
#endregion
#endregion
}
}