首先我们先了解微信支付的几种方式:https://pay.weixin.qq.com/wiki/doc/api/index.html
然后打开相应开发文档查看请求参数:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
注:此文章用的是 公众号支付
/// <summary>
/// PostPay 的摘要说明
/// </summary>
public class PostPay1 : IHttpHandler
{
Log log = new Log();//记录日志
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string openid = context.Request.Params["openid"];//小程序传参
string totalfee =context.Request.Params["totalfee"];//订单金额
string body = context.Request.Params["body"]; //小程序传参
string transaction_id = context.Request.Params["pay_id"];//微信订单ID
string appid = ConfigurationManager.AppSettings["appid"];
string secret = ConfigurationManager.AppSettings["secret"];//小程序秘钥
log.write("openid:" + openid);
string key = ConfigurationManager.AppSettings["key"];//支付秘钥
string mch_id = ConfigurationManager.AppSettings["mch_id"];//商户号
string ip = ConfigurationManager.AppSettings["ip"];//服务器IP
string PayResulturl = ConfigurationManager.AppSettings["PayResulturl"];//微信返回接收信息的url地址
string output = "";
if ((openid != null) && (openid != ""))
{
double dubamount;
double.TryParse(totalfee, out dubamount);
string nonce_str = GetRandomString(20);
//新增订单信息
Random Random = new Random();
var dic = new Dictionary<string, string>
{
{"appid", appid},
{"mch_id", mch_id},
{"nonce_str",nonce_str /*Random.Next().ToString()*/},
{"body",body},
{"out_trade_no","M"+DateTime.Now.ToString("yyyyMMddHHmmssfff") + Random.Next(999).ToString()},//订单号码
{"total_fee",(dubamount).ToString()},//订单金额
{"spbill_create_ip",ip},//服务器的IP地址
{"notify_url",PayResulturl},//异步通知的地址,不能带参数
{"trade_type","JSAPI" },
{"openid",openid},
{"fee_type", "CNY"}
};
//加入签名
string sign = GetSignString(dic);
dic.Add("sign", sign);
log.write("sign");
var sb = new StringBuilder();
sb.Append("<xml>");
foreach (var d in dic)
{
sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">");
}
sb.Append("</xml>");
CookieCollection coo = new CookieCollection();
Encoding en = Encoding.GetEncoding("UTF-8");
HttpWebResponse response = CreatePostHttpResponse("https://api.mch.weixin.qq.com/pay/unifiedorder", sb.ToString(), en);
var xml = new XmlDocument();
//打印返回值
Stream stream = response.GetResponseStream(); //获取响应的字符串流
StreamReader sr = new StreamReader(stream); //创建一个stream读取流
string html = sr.ReadToEnd(); //从头读到尾,放到字符串html
log.write("html:" + html);
//Json转换字符串
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();
string return_msg = ds.Tables[0].Rows[0]["return_msg"].ToString();
if (return_code.ToUpper() == "SUCCESS")
{
log.write("result_code:" + ds.Tables[0].Rows[0]["result_code"].ToString());
//通信成功
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);
log.write("signapp:" + signapp);
context.Response.Write(signapp);
}
}
else
{
log.write(this.GetType().ToString()+"UnifiedOrder respone error");
throw new Exception("UnifiedOrder respone error");
}
}
log.write("output:" + output);
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 = new Random();
for (int i = 0; i < CodeCount; i++)
{
if (temp != -1)
{
rand = new Random(temp * i * ((int)DateTime.Now.Ticks));
}
int t = rand.Next(allCharArray.Length - 1);
while (temp == t)
{
t = rand.Next(allCharArray.Length - 1);
}
temp = t;
RandomCode += allCharArray[t];
}
return RandomCode;
}
public static string GetWebClientIp()
{
string userIP = "IP";
try
{
if (System.Web.HttpContext.Current == null
|| System.Web.HttpContext.Current.Request == null
|| System.Web.HttpContext.Current.Request.ServerVariables == null)
return "";
string CustomerIP = "";
//CDN加速后取到的IP
CustomerIP = System.Web.HttpContext.Current.Request.Headers["Cdn-Src-Ip"];
if (!string.IsNullOrEmpty(CustomerIP))
{
return CustomerIP;
}
CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (!String.IsNullOrEmpty(CustomerIP))
return CustomerIP;
if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null)
{
CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (CustomerIP == null)
CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
}
else
{
CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
}
if (string.Compare(CustomerIP, "unknown", true) == 0)
return System.Web.HttpContext.Current.Request.UserHostAddress;
return CustomerIP;
}
catch { }
return userIP;
}
private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
return true;
}
public static HttpWebResponse CreatePostHttpResponse(string url, string datas, Encoding charset)
{
HttpWebRequest request = null;
//HTTPSQ请求
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
request = WebRequest.Create(url) as HttpWebRequest;
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
//如果需要POST数据
//if (!(parameters == null || parameters.Count == 0))
//{
StringBuilder buffer = new StringBuilder();
//int i = 0;
//foreach (string key in parameters.Keys)
//{
// if (i > 0)
// {
// buffer.AppendFormat("&{0}={1}", key, parameters[key]);
// }
// else
// {
// buffer.AppendFormat("{0}={1}", key, parameters[key]);
// }
// i++;
//}
buffer.AppendFormat(datas);
byte[] data = charset.GetBytes(buffer.ToString());
using (Stream stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
//}
return request.GetResponse() as HttpWebResponse;
}
/// <summary>
/// 获取签名字符串
/// </summary>
/// <returns></returns>
public string GetSignString(Dictionary<string, string> dic)
{
string key = System.Web.Configuration.WebConfigurationManager.AppSettings["key"].ToString();//商户平台 API安全里面设置的KEY 32位长度
//排序
dic = dic.OrderBy(d => d.Key).ToDictionary(d => d.Key, d => d.Value);
//连接字段
var sign = dic.Aggregate("", (current, d) => current + (d.Key + "=" + d.Value + "&"));
sign += "key=" + key;
//MD5
// sign = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sign, "MD5").ToUpper();
System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
sign = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(sign))).Replace("-", null);
return sign;
}
/// <summary>
/// 获取时间戳
/// </summary>
/// <returns></returns>
public static string GetTimeStamp()
{
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
}
/// <summary>
/// notify_url 的摘要说明
/// </summary>
public class notify_url : IHttpHandler
{
public string return_result = "";
Log log = new Log();
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
log.write("notify_url");
String xmlData = getPostStr();//获取请求数据
if (xmlData == "")
{
}
else
{
log.write("xmlData:" + xmlData);
var dic = new Dictionary<string, string>
{
{"return_code", "SUCCESS"},
{"return_msg","OK"}
};
var sb = new StringBuilder();
sb.Append("<xml>");
foreach (var d in dic)
{
sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">");
}
sb.Append("</xml>");
//把数据重新返回给客户端
DataSet ds = new DataSet();
StringReader stram = new StringReader(xmlData);
XmlTextReader datareader = new XmlTextReader(stram);
ds.ReadXml(datareader);
if (ds.Tables[0].Rows[0]["return_code"].ToString() == "SUCCESS")
{
string wx_appid = "";//微信开放平台审核通过的应用APPID
string wx_mch_id ="";//微信支付分配的商户号
string wx_nonce_str = "";// 随机字符串,不长于32位
string wx_sign = "";//签名,详见签名算法
string wx_result_code = "";//SUCCESS/FAIL
string wx_return_code = "";
string wx_openid = "";//用户在商户appid下的唯一标识
string wx_is_subscribe = "";//用户是否关注公众账号,Y-关注,N-未关注,仅在公众账号类型支付有效
string wx_trade_type = "";// APP
string wx_bank_type = "";// 银行类型,采用字符串类型的银行标识,银行类型见银行列表
string wx_fee_type = "";// 货币类型,符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
string wx_transaction_id = "";//微信支付订单号
string wx_out_trade_no = "";//商户系统的订单号,与请求一致。
string wx_time_end = "";// 支付完成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
int wx_total_fee = -1;// 订单总金额,单位为分
int wx_cash_fee = -1;//现金支付金额订单现金支付金额,详见支付金额
#region 数据解析
//列 是否存在
string signstr = "";//需要前面的字符串
//wx_appid
if (ds.Tables[0].Columns.Contains("appid"))
{
wx_appid = ds.Tables[0].Rows[0]["appid"].ToString();
if (!string.IsNullOrEmpty(wx_appid))
{
signstr += "appid=" + wx_appid;
}
}
//wx_bank_type
if (ds.Tables[0].Columns.Contains("bank_type"))
{
wx_bank_type = ds.Tables[0].Rows[0]["bank_type"].ToString();
if (!string.IsNullOrEmpty(wx_bank_type))
{
signstr += "&bank_type=" + wx_bank_type;
}
}
//wx_cash_fee
if (ds.Tables[0].Columns.Contains("cash_fee"))
{
wx_cash_fee = Convert.ToInt32(ds.Tables[0].Rows[0]["cash_fee"].ToString());
signstr += "&cash_fee=" + wx_cash_fee;
}
//wx_fee_type
if (ds.Tables[0].Columns.Contains("fee_type"))
{
wx_fee_type = ds.Tables[0].Rows[0]["fee_type"].ToString();
if (!string.IsNullOrEmpty(wx_fee_type))
{
signstr += "&fee_type=" + wx_fee_type;
}
}
//wx_is_subscribe
if (ds.Tables[0].Columns.Contains("is_subscribe"))
{
wx_is_subscribe = ds.Tables[0].Rows[0]["is_subscribe"].ToString();
if (!string.IsNullOrEmpty(wx_is_subscribe))
{
signstr += "&is_subscribe=" + wx_is_subscribe;
}
}
//wx_mch_id
if (ds.Tables[0].Columns.Contains("mch_id"))
{
wx_mch_id = ds.Tables[0].Rows[0]["mch_id"].ToString();
if (!string.IsNullOrEmpty(wx_mch_id))
{
signstr += "&mch_id=" + wx_mch_id;
}
}
//wx_nonce_str
if (ds.Tables[0].Columns.Contains("nonce_str"))
{
wx_nonce_str = ds.Tables[0].Rows[0]["nonce_str"].ToString();
if (!string.IsNullOrEmpty(wx_nonce_str))
{
signstr += "&nonce_str=" + wx_nonce_str;
}
}
//wx_openid
if (ds.Tables[0].Columns.Contains("openid"))
{
wx_openid = ds.Tables[0].Rows[0]["openid"].ToString();
if (!string.IsNullOrEmpty(wx_openid))
{
signstr += "&openid=" + wx_openid;
}
}
//wx_out_trade_no
if (ds.Tables[0].Columns.Contains("out_trade_no"))
{
wx_out_trade_no = ds.Tables[0].Rows[0]["out_trade_no"].ToString();
if (!string.IsNullOrEmpty(wx_out_trade_no))
{
signstr += "&out_trade_no=" + wx_out_trade_no;
}
}
//wx_result_code
if (ds.Tables[0].Columns.Contains("result_code"))
{
wx_result_code = ds.Tables[0].Rows[0]["result_code"].ToString();
if (!string.IsNullOrEmpty(wx_result_code))
{
signstr += "&result_code=" + wx_result_code;
}
}
//wx_result_code
if (ds.Tables[0].Columns.Contains("return_code"))
{
wx_return_code = ds.Tables[0].Rows[0]["return_code"].ToString();
if (!string.IsNullOrEmpty(wx_return_code))
{
signstr += "&return_code=" + wx_return_code;
}
}
//wx_sign
if (ds.Tables[0].Columns.Contains("sign"))
{
wx_sign = ds.Tables[0].Rows[0]["sign"].ToString();
//if (!string.IsNullOrEmpty(wx_sign))
//{
// signstr += "&sign=" + wx_sign;
//}
}
//wx_time_end
if (ds.Tables[0].Columns.Contains("time_end"))
{
wx_time_end = ds.Tables[0].Rows[0]["time_end"].ToString();
if (!string.IsNullOrEmpty(wx_time_end))
{
signstr += "&time_end=" + wx_time_end;
}
}
//wx_total_fee
if (ds.Tables[0].Columns.Contains("total_fee"))
{
wx_total_fee = Convert.ToInt32(ds.Tables[0].Rows[0]["total_fee"].ToString());
signstr += "&total_fee=" + wx_total_fee;
}
//wx_trade_type
if (ds.Tables[0].Columns.Contains("trade_type"))
{
wx_trade_type = ds.Tables[0].Rows[0]["trade_type"].ToString();
if (!string.IsNullOrEmpty(wx_trade_type))
{
signstr += "&trade_type=" + wx_trade_type;
}
}
//wx_transaction_id
if (ds.Tables[0].Columns.Contains("transaction_id"))
{
wx_transaction_id = ds.Tables[0].Rows[0]["transaction_id"].ToString();
if (!string.IsNullOrEmpty(wx_transaction_id))
{
signstr += "&transaction_id=" + wx_transaction_id;
}
}
log.write(signstr);
#endregion
//追加key 密钥
signstr += "&key=" + System.Web.Configuration.WebConfigurationManager.AppSettings["key"].ToString();
//签名正确
string orderStrwhere = "ordernumber='" + wx_out_trade_no + "'";
if (wx_sign == System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(signstr, "MD5").ToUpper())
{
//签名正确 处理订单操作逻辑
using (TransactionScope sc = new TransactionScope())
{
//逻辑操作
}
catch (Exception ex)
{
log.write("retrun_msg:" + ex.Message);
context.Response.Write("error:"+ex.Message);
}
}
}
else
{
//追加备注信息
log.write("签名错误 :" + ds.Tables[0].Rows[0]["return_msg"].ToString());
context.Response.Write("error:"+ ds.Tables[0].Rows[0]["return_msg"].ToString());
}
}
else
{
// 返回信息,如非空,为错误原因 签名失败 参数格式校验错误
string return_msg = ds.Tables[0].Rows[0]["return_msg"].ToString();
context.Response.Write("error:" + return_msg);
}
return_result = sb.ToString();
}
}
public bool IsReusable
{
get
{
return false;
}
}
//获得Post过来的数据
public string getPostStr()
{
Int32 intLen = Convert.ToInt32(System.Web.HttpContext.Current.Request.InputStream.Length);
byte[] b = new byte[intLen];
System.Web.HttpContext.Current.Request.InputStream.Read(b, 0, intLen);
return System.Text.Encoding.UTF8.GetString(b);
}
}