微信小程序支付功能的开发的时候坑比较多,不过对于钱的事谨慎也是好事。网上关于小程序支付的实例很多,但是大多多少有些问题,C#开发的更少。此篇文档的目的是讲开发过程中遇到的问题做一个备注,也方便其他开发的同学作为参考!
1、首先建议把官方文档支付部分看上三遍,每个细节都不要放过,因为任何一个点和微信要求不符都会导致支付不成功。https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=3_1
2、经过验证的微信支付功能,会需要一些商户号、支付秘钥等,不要搞混。
3、经常遇到的是“签名错误”,请仔细看需要传送的xml参数及取值规则是否符合微信规则。微信有个验证工具可以验证发送的xml字段是否合法。
下面上代码:
web.config
<add key="ConnectionString" value="server=127.0.0.1;database=;uid=sa;pwd="/>
<add key="ConnectionString2" value="server=127.0.0.1;database=codematic2;uid=sa;pwd=1"/>
<add key="appid" value=""/>//appid
<add key="secret" value=""/>//小程序秘钥
<add key="mch_id" value=""/>//商户号
<add key="key" value=""/>//支付秘钥
<add key="ip" value=""/>//服务器IP
<add key="PayResulturl" value=""/>//微信返回接收信息的url地址
</appSettings>
支付后台xiadan.ashx
<%@ WebHandler Language="C#" Class="xiadan" %>
using System;
using System.Web;
using System.Net;
using System.IO;
using System.Configuration;
using Maticsoft.Model;
using Maticsoft.BLL;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Serialization;
using System.Xml;
using System.Collections.Generic;
using System.Data;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Linq;
using Newtonsoft.Json;
public class xiadan : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string openid = context.Request.Params["openid"];
string ordertime = context.Request.Params["ordertime"];
string appid = ConfigurationManager.AppSettings["appid"];
string secret = ConfigurationManager.AppSettings["secret"];
string key = ConfigurationManager.AppSettings["key"];
string mch_id = ConfigurationManager.AppSettings["mch_id"];
string ip = ConfigurationManager.AppSettings["ip"];
string PayResulturl = ConfigurationManager.AppSettings["PayResulturl"];
string roomid = context.Request.Params["roomid"];
string aa = "-押金";////商品描述交易字段格式根据不同的应用场景按照以下格式:APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。
string strcode = aa;
byte[] buffer = Encoding.UTF8.GetBytes(strcode);
string body = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
string totalfee = context.Request.Params["totalfee"];
string output = "";
if ((context.Request.Params["openid"] != null) && (context.Request.Params["openid"] != ""))
{
//OrderInfo order = new OrderInfo();
//order.appid = appid;
System.Random Random = new System.Random();
var dic = new Dictionary<string, string>
{
{"appid", appid},
{"mch_id", mch_id},
{"nonce_str", GetRandomString(20)/*Random.Next().ToString()*/},
{"body",body},
{"out_trade_no",roomid + DateTime.Now.ToString("yyyyMMddHHmmssfff") + Random.Next(999).ToString()},//商户自己的订单号码
{"total_fee",totalfee},
{"spbill_create_ip",ip},//服务器的IP地址
{"notify_url",PayResulturl},//异步通知的地址,不能带参数
{"trade_type","JSAPI" },
{"openid",openid}
};
//加入签名
dic.Add("sign", GetSignString(dic));
var sb = new StringBuilder();
sb.Append("<xml>");
foreach (var d in dic)
{
sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">");
}
sb.Append("</xml>");
var xml = new XmlDocument();
// xml.LoadXml(GetPostString("https://api.mch.weixin.qq.com/pay/unifiedorder", sb.ToString()));
CookieCollection coo = new CookieCollection();
Encoding en = Encoding.GetEncoding("UTF-8");
HttpWebResponse response = CreatePostHttpResponse("https://api.mch.weixin.qq.com/pay/unifiedorder", sb.ToString(), en);
//打印返回值
Stream stream = response.GetResponseStream(); //获取响应的字符串流
StreamReader sr = new StreamReader(stream); //创建一个stream读取流
string html = sr.ReadToEnd(); //从头读到尾,放到字符串html
//Console.WriteLine(html);
xml.LoadXml(html);
//对请求返回值 进行处理
var root = xml.DocumentElement;
DataSet ds = new DataSet();
StringReader stram = new StringReader(html);
XmlTextReader reader = new XmlTextReader(stram);
ds.ReadXml(reader);
string return_code = ds.Tables[0].Rows[0]["return_code"].ToString();
if (return_code.ToUpper() == "SUCCESS")
{
//通信成功
string result_code = ds.Tables[0].Rows[0]["result_code"].ToString();//业务结果
if (result_code.ToUpper() == "SUCCESS")
{
var res = new Dictionary<string, string>
{
{"appId", appid},
{"timeStamp", GetTimeStamp()},
{"nonceStr", dic["nonce_str"]},
{"package", "prepay_id="+ds.Tables[0].Rows[0]["prepay_id"].ToString()},
{"signType", "MD5"}
};
//在服务器上签名
res.Add("paySign", GetSignString(res));
// string signapp = res.ToString();
string signapp = JsonConvert.SerializeObject(res);
if ((context.Request.Params["openid"] != null) && (context.Request.Params["openid"] != ""))
{
//存储订单信息
Maticsoft.Model.order_history oh = new Maticsoft.Model.order_history();
//oh.shop_id =
oh.room_id = Convert.ToInt32(roomid);
oh.pay_price = Convert.ToDecimal(totalfee);
oh.out_trade_no = dic["out_trade_no"];
oh.order_timestart = Convert.ToDateTime(ordertime);
oh.openid = openid;
oh.creating_date = DateTime.Now;
Maticsoft.BLL.order_history bll = new Maticsoft.BLL.order_history();
bll.Add(oh);
}
context.Response.Write(signapp);
}
}
}
context.Response.Write(output);
}
public bool IsReusable
{
get
{
return false;
}
}
public string GetMd5Hash(String input)
{
if (input == null)
{
return null;
}
MD5 md5Hash = MD5.Create();
// 将输入字符串转换为字节数组并计算哈希数据
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
// 创建一个 Stringbuilder 来收集字节并创建字符串
StringBuilder sBuilder = new StringBuilder();
// 循环遍历哈希数据的每一个字节并格式化为十六进制字符串
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString());
}
// 返回十六进制字符串
return sBuilder.ToString();
}
/// <summary>
/// 对象序列化成 XML String
/// </summary>
public static string XmlSerialize<T>(T obj)
{
string xmlString = string.Empty;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
xmlSerializer.Serialize(ms, obj);
xmlString = Encoding.UTF8.GetString(ms.ToArray());
}
return xmlString;
}
/// <summary>
/// 从字符串里随机得到,规定个数的字符串.
/// </summary>
/// <param name="allChar"></param>
/// <param name="CodeCount"></param>
/// <returns></returns>
public static string GetRandomString(int CodeCount)
{
string allChar = "1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,i,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";
string[] allCharArray = allChar.Split(\',\');
string RandomCode = "";
int temp = -1;
Random rand =