支付寶、微信支付(.NET)
專案結構
Core
基礎類庫資料夾
Common
BizResult.cs
using AW.Pay.Core.Enum;
namespace AW.Pay.Core.Common
{
/// <summary>
/// HTTP請求返回資訊
/// </summary>
/// <typeparam name="T"></typeparam>
public class BizResult<T>
{
public BizResult(EnumBizCode resultCode = EnumBizCode.Success, string message = "操作成功")
{
Code = resultCode;
Message = message;
}
/// <summary>
/// 編碼
/// </summary>
public EnumBizCode Code { get; set; }
/// <summary>
/// 返回資訊
/// </summary>
public string Message { get; set; } = "";
/// <summary>
/// 返回物件
/// </summary>
public T ReturnObject { get; set; }
}
}
Config.cs
using System.Configuration;
namespace AW.Pay.Core
{
public static class AlipayConfig
{
#region Alipay config
public static string ALIPay_URL = ConfigurationManager.AppSettings["ALIPay_URL"];
public static string ALIPay_NotifyURL = ConfigurationManager.AppSettings["ALIPay_NotifyURL"];
public static string ALIPay_ErrorURL = ConfigurationManager.AppSettings["ALIPay_ErrorURL"];
public static string ALI_PARTER = ConfigurationManager.AppSettings["ALI_PARTER"];
public static string ALI_KEY = ConfigurationManager.AppSettings["ALI_KEY"];
public static string ALI_ACCOUNT = ConfigurationManager.AppSettings["ALI_ACCOUNT"];
public static string CHARTSET = "utf-8"; //固定值
public static string PAYMENT_TYPE = "1"; //固定值
public static string ALI_SELLERID = ConfigurationManager.AppSettings["ALI_SELLERID"];
public static string ALI_SELLEREMAIL = ConfigurationManager.AppSettings["ALI_SELLEREMAIL"];
public static string ALI_HTTPS_VERYFY_URL = ConfigurationManager.AppSettings["ALI_HTTPS_VERYFY_URL"];
public static string ALIPay_WAP_SERVICE = ConfigurationManager.AppSettings["ALIPay_WAP_SERVICE"];
public static string ALIPay_WEB_SERVICE = ConfigurationManager.AppSettings["ALIPay_WEB_SERVICE"];
public static string ALIPay_MOBILE_SERVICE = ConfigurationManager.AppSettings["ALIPay_MOBILE_SERVICE"];
public static string ALIPay_RSA_PUBLICKEY = ConfigurationManager.AppSettings["ALIPay_RSA_PUBLICKEY"];
public static string ALIPay_RSA_PRIVATEKEY = ConfigurationManager.AppSettings["ALIPay_RSA_PRIVATEKEY"];
public static string ALIPay_RSA_ALI_PUBLICKEY = ConfigurationManager.AppSettings["ALIPay_RSA_ALI_PUBLICKEY"];
#endregion
}
public static class WepayConfig
{
public static string WEPAY_CHARTSET = "utf-8";
public static string WEPAY_PAY_URL = ConfigurationManager.AppSettings["WEPAY_PAY_URL"]; //統一下單URL
public static string WEPAY_ORDERQUERY_URL = ConfigurationManager.AppSettings["WEPAY_ORDERQUERY_URL"];
#region 微信開發者平臺(APP支付)
public static string WEPAY_APP_APPID = ConfigurationManager.AppSettings["WEPAY_MP_APPID"];
public static string WEPAY_APP_MCH_ID = ConfigurationManager.AppSettings["WEPAY_MP_MCH_ID"];
public static string WEPAY_APP_NOTIFY_URL = ConfigurationManager.AppSettings["WEPAY_MP_NOTIFY_URL"];
public static string WEPAY_APP_URL = ConfigurationManager.AppSettings["WEPAY_MP_URL"];
public static string WEPAY_APP_KEY = ConfigurationManager.AppSettings["WEPAY_APP_KEY"];
#endregion
#region 微信公眾平臺(掃碼、公眾號支付)
public static string WEPAY_WEB_APPID = ConfigurationManager.AppSettings["WEPAY_WEB_APPID"];
public static string WEPAY_WEB_MCH_ID = ConfigurationManager.AppSettings["WEPAY_WEB_MCH_ID"];
public static string WEPAY_WEB_NOTIFY_URL = ConfigurationManager.AppSettings["WEPAY_WEB_NOTIFY_URL"];
public static string WEPAY_WEB_URL = ConfigurationManager.AppSettings["WEPAY_WEB_URL"];
public static string WEPAY_WEB_KEY = ConfigurationManager.AppSettings["WEPAY_WEB_KEY"];
#endregion
}
}
HTTPHelper.cs
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
namespace AW.Pay.Core
{
public static class HTTPHelper
{
public static string Post(string url, string content, string contentType = "application/x-www-form-urlencoded")
{
var result = string.Empty;
try
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType));
var stringContent = new StringContent(content, Encoding.UTF8);
var response = client.PostAsync(url, stringContent).Result;
result = response.Content.ReadAsStringAsync().Result;
}
}
catch (Exception e)
{
throw new Exception("POST請求錯誤" + e);
}
return result;
}
public static string Get(string url, int timeout, string contentType = "application/x-www-form-urlencoded")
{
var result = string.Empty;
try
{
using (var client = new HttpClient())
{
client.Timeout = new TimeSpan(0, 0, 0, 0, timeout);
var response = client.GetAsync(url).Result;
result = response.Content.ReadAsStringAsync().Result;
}
;
}
catch (Exception e)
{
throw new Exception("GET請求錯誤" + e);
}
return result;
}
}
}
MD5Helper.cs
using System.Security.Cryptography;
using System.Text;
namespace AW.Pay.Core
{
public sealed class MD5Helper
{
public static string Sign(string prestr, string _input_charset)
{
var sb = new StringBuilder(32);
MD5 md5 = new MD5CryptoServiceProvider();
var t = md5.ComputeHash(Encoding.GetEncoding(_input_charset).GetBytes(prestr));
for (var i = 0; i < t.Length; i++)
{
sb.Append(t[i].ToString("x").PadLeft(2, '0'));
}
return sb.ToString();
}
}
}
RSAFromPkcs8.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace AW.Pay.Core
{
public sealed class RSAFromPkcs8
{
/// <summary>
/// 簽名
/// </summary>
/// <param name="content">需要簽名的內容</param>
/// <param name="privateKey">私鑰</param>
/// <param name="input_charset">編碼格式</param>
/// <returns></returns>
public static string sign(string content, string privateKey, string input_charset)
{
var code = Encoding.GetEncoding(input_charset);
var Data = code.GetBytes(content);
var rsa = DecodePemPrivateKey(privateKey);
SHA1 sh = new SHA1CryptoServiceProvider();
var signData = rsa.SignData(Data, sh);
return Convert.ToBase64String(signData);
}
/// <summary>
/// 驗證簽名
/// </summary>
/// <param name="content">需要驗證的內容</param>
/// <param name="signedString">簽名結果</param>
/// <param name="publicKey">公鑰</param>
/// <param name="input_charset">編碼格式</param>
/// <returns></returns>
public static bool verify(string content, string signedString, string publicKey, string input_charset)
{
var result = false;
var code = Encoding.GetEncoding(input_charset);
var Data = code.GetBytes(content);
var data = Convert.FromBase64String(signedString);
var paraPub = ConvertFromPublicKey(publicKey);
var rsaPub = new RSACryptoServiceProvider();
rsaPub.ImportParameters(paraPub);
SHA1 sh = new SHA1CryptoServiceProvider();
result = rsaPub.VerifyData(Data, sh, data);
return result;
}
/// <summary>
/// 用RSA解密
/// </summary>
/// <param name="resData">待解密字串</param>
/// <param name="privateKey">私鑰</param>
/// <param name="input_charset">編碼格式</param>
/// <returns>解密結果</returns>
public static string decryptData(string resData, string privateKey, string input_charset)
{
var DataToDecrypt = Convert.FromBase64String(resData);
var result = new List<byte>();
for (var j = 0; j < DataToDecrypt.Length / 128; j++)
{
var buf = new byte[128];
for (var i = 0; i < 128; i++)
{
buf[i] = DataToDecrypt[i + 128 * j];
}
result.AddRange(decrypt(buf, privateKey, input_charset));
}
var source = result.ToArray();
var asciiChars = new char[Encoding.GetEncoding(input_charset).GetCharCount(source, 0, source.Length)];
Encoding.GetEncoding(input_charset).GetChars(source, 0, source.Length, asciiChars, 0);
return new string(asciiChars);
}
private static byte[] decrypt(byte[] data, string privateKey, string input_charset)
{
var rsa = DecodePemPrivateKey(privateKey);
SHA1 sh = new SHA1CryptoServiceProvider();
return rsa.Decrypt(data, false);
}
/// <summary>
/// 解析java生成的pem檔案私鑰
/// </summary>
/// <param name="pemstr"></param>
/// <returns></returns>
private static RSACryptoServiceProvider DecodePemPrivateKey(string pemstr)
{
byte[] pkcs8privatekey;
pkcs8privatekey = Convert.FromBase64String(pemstr);
if (pkcs8privatekey != null)
{
var rsa = DecodePrivateKeyInfo(pkcs8privatekey);
return rsa;
}
return null;
}
private static RSACryptoServiceProvider DecodePrivateKeyInfo(byte[] pkcs8)
{
byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
var seq = new byte[15];
var mem = new MemoryStream(pkcs8);
var lenstream = (int)mem.Length;
var binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
byte bt = 0;
ushort twobytes = 0;
try
{
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8230)
binr.ReadInt16(); //advance 2 bytes
else
return null;
bt = binr.ReadByte();
if (bt != 0x02)
return null;
twobytes = binr.ReadUInt16();
if (twobytes != 0x0001)
return null;
seq = binr.ReadBytes(15); //read the Sequence OID
if (!CompareBytearrays(seq, SeqOID)) //make sure Sequence for OID is correct
return null;
bt = binr.ReadByte();
if (bt != 0x04) //expect an Octet string
return null;
bt = binr.ReadByte(); //read next byte, or next 2 bytes is 0x81 or 0x82; otherwise bt is the byte count
if (bt == 0x81)
binr.ReadByte();
else if (bt == 0x82)
binr.ReadUInt16();
//------ at this stage, the remaining sequence should be the RSA private key
var rsaprivkey = binr.ReadBytes((int)(lenstream - mem.Position));
var rsacsp = DecodeRSAPrivateKey(rsaprivkey);
return rsacsp;
}
catch (Exception)
{
return null;
}
finally
{
binr.Close();
}
}
private static bool CompareBytearrays(byte[] a, byte[] b)
{
if (a.Length != b.Length)
return false;
var i = 0;
foreach (var c in a)
{
if (c != b[i])
return false;
i++;
}
return true;
}
private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
{
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
// --------- Set up stream to decode the asn.1 encoded RSA private key ------
var mem = new MemoryStream(privkey);
var binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
byte bt = 0;
ushort twobytes = 0;
var elems = 0;
try
{
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8230)
binr.ReadInt16(); //advance 2 bytes
else
return null;
twobytes = binr.ReadUInt16();
if (twobytes != 0x0102) //version number
return null;
bt = binr.ReadByte();
if (bt != 0x00)
return null;
//------ all private key components are Integer sequences ----
elems = GetIntegerSize(binr);
MODULUS = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
E = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
D = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
P = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
Q = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
DP = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
DQ = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
IQ = binr.ReadBytes(elems);
// ------- create RSACryptoServiceProvider instance and initialize with public key -----
var RSA = new RSACryptoServiceProvider();
var RSAparams = new RSAParameters();
RSAparams.Modulus = MODULUS;
RSAparams.Exponent = E;
RSAparams.D = D;
RSAparams.P = P;
RSAparams.Q = Q;
RSAparams.DP = DP;
RSAparams.DQ = DQ;
RSAparams.InverseQ = IQ;
RSA.ImportParameters(RSAparams);
return RSA;
}
catch (Exception)
{
return null;
}
finally
{
binr.Close();
}
}
private static int GetIntegerSize(BinaryReader binr)
{
byte bt = 0;
byte lowbyte = 0x00;
byte highbyte = 0x00;
var count = 0;
bt = binr.ReadByte();
if (bt != 0x02) //expect integer
return 0;
bt = binr.ReadByte();
if (bt == 0x81)
count = binr.ReadByte(); // data size in next byte
else if (bt == 0x82)
{
highbyte = binr.ReadByte(); // data size in next 2 bytes
lowbyte = binr.ReadByte();
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
count = BitConverter.ToInt32(modint, 0);
}
else
{
count = bt; // we already have the data size
}
while (binr.ReadByte() == 0x00)
{
//remove high order zeros in data
count -= 1;
}
binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte
return count;
}
#region 解析.net 生成的Pem
private static RSAParameters ConvertFromPublicKey(string pemFileConent)
{
var keyData = Convert.FromBase64String(pemFileConent);
if (keyData.Length < 162)
{
throw new ArgumentException("pem file content is incorrect.");
}
var pemModulus = new byte[128];
var pemPublicExponent = new byte[3];
Array.Copy(keyData, 29, pemModulus, 0, 128);
Array.Copy(keyData, 159, pemPublicExponent, 0, 3);
var para = new RSAParameters();
para.Modulus = pemModulus;
para.Exponent = pemPublicExponent;
return para;
}
private static RSAParameters ConvertFromPrivateKey(string pemFileConent)
{
var keyData = Convert.FromBase64String(pemFileConent);
if (keyData.Length < 609)
{
throw new ArgumentException("pem file content is incorrect.");
}
var index = 11;
var pemModulus = new byte[128];
Array.Copy(keyData, index, pemModulus, 0, 128);
index += 128;
index += 2; //141
var pemPublicExponent = new byte[3];
Array.Copy(keyData, index, pemPublicExponent, 0, 3);
index += 3;
index += 4; //148
var pemPrivateExponent = new byte[128];
Array.Copy(keyData, index, pemPrivateExponent, 0, 128);
index += 128;
index += (int)keyData[index + 1] == 64 ? 2 : 3; //279
var pemPrime1 = new byte[64];
Array.Copy(keyData, index, pemPrime1, 0, 64);
index += 64;
index += (int)keyData[index + 1] == 64 ? 2 : 3; //346
var pemPrime2 = new byte[64];
Array.Copy(keyData, index, pemPrime2, 0, 64);
index += 64;
index += (int)keyData[index + 1] == 64 ? 2 : 3; //412/413
var pemExponent1 = new byte[64];
Array.Copy(keyData, index, pemExponent1, 0, 64);
index += 64;
index += (int)keyData[index + 1] == 64 ? 2 : 3; //479/480
var pemExponent2 = new byte[64];
Array.Copy(keyData, index, pemExponent2, 0, 64);
index += 64;
index += (int)keyData[index + 1] == 64 ? 2 : 3; //545/546
var pemCoefficient = new byte[64];
Array.Copy(keyData, index, pemCoefficient, 0, 64);
var para = new RSAParameters();
para.Modulus = pemModulus;
para.Exponent = pemPublicExponent;
para.D = pemPrivateExponent;
para.P = pemPrime1;
para.Q = pemPrime2;
para.DP = pemExponent1;
para.DQ = pemExponent2;
para.InverseQ = pemCoefficient;
return para;
}
#endregion
}
}
Enum
列舉類資料夾
EnumAliPayTradeType.cs
namespace AW.Pay.Core
{
/// <summary>
/// AliPay交易型別
/// </summary>
public enum EnumAliPayTradeType
{
/// <summary>
/// 網站支付
/// </summary>
Website = 0,
/// <summary>
/// wap支付
/// </summary>
Wap,
/// <summary>
/// APP支付
/// </summary>
APP
}
}
EnumBizCode.cs
namespace AW.Pay.Core.Enum
{
/// <summary>
/// 業務返回code
/// </summary>
public enum EnumBizCode
{
/// <summary>
/// 成功
/// </summary>
Success = 1000,
/// <summary>
/// 失敗
/// </summary>
Failed
}
}
EnumSignType.cs
namespace AW.Pay.Core
{
public enum EnumSignType
{
/// <summary>
/// MD5
/// </summary>
MD5 = 0,
/// <summary>
/// RSA
/// </summary>
RSA
}
}
EnumWePayTradeType.cs
namespace AW.Pay.Core.Enum
{
public enum EnumWePayTradeType
{
/// <summary>
/// 公眾號支付
/// </summary>
JSAPI = 0,
/// <summary>
/// 原生掃碼支付
/// </summary>
NATIVE,
/// <summary>
/// app支付
/// </summary>
APP,
/// <summary>
/// wap支付(瀏覽器呼叫微信app,目前騰訊還未對外開放)
/// </summary>
WAP
}
}
Interface
IAlipay.cs
using System.Web;
using AW.Pay.Core.Model;
namespace AW.Pay.Core.Interface
{
public interface IAlipay
{
/// <summary>
/// 建立支付寶支付
/// </summary>
/// <param name="orderNo">訂單號</param>
/// <param name="subject">標題</param>
/// <param name="payAmount">支付金額</param>
/// <param name="tradeType">交易型別(網站支付、wap支付、APP支付)</param>
/// <returns></returns>
string BuildAliPay(string orderNo, string subject, decimal payAmount, EnumAliPayTradeType tradeType);
/// <summary>
/// 驗證支付寶回撥,並獲取相關返回引數
/// </summary>
/// <param name="request">HTTP請求</param>
/// <param name="model">當驗證成功後,獲取主要返回引數</param>
/// <returns>驗證結果</returns>
bool VerifyReturnURL(HttpRequestBase request, out AliPayReturnModel model);
/// <summary>
/// 驗證支付寶非同步通知,並獲取相關返回引數
/// </summary>
/// <param name="request">HTTP請求</param>
/// <param name="model">當驗證成功後,獲取主要返回引數</param>
/// <returns>驗證結果</returns>
bool VerfyNotify(HttpRequestBase request, out AliPayReturnModel model);
}
}
IWePay.cs
using System.Web;
using AW.Pay.Core.Enum;
using AW.Pay.Core.Model;
namespace AW.Pay.Core.Interface
{
public interface IWePay
{
/// <summary>
/// 建立微信支付
/// </summary>
/// <param name="orderNo">訂單號</param>
/// <param name="productName">產品名稱</param>
/// <param name="totalFee">總金額,單位分</param>
/// <param name="customerIP">呼叫IP</param>
/// <param name="tradeType">交易型別(公眾號支付、掃碼支付、APP、WAP支付)</param>
/// <returns>
/// 掃碼支付:返回支付URL
/// APP支付:返回Json字串,包含支付sdk支付引數
/// 公眾號支付&WAP支付:暫未實現
/// </returns>
string BuildWePay(string orderNo, string productName, int totalFee, string customerIP,
EnumWePayTradeType tradeType);
/// <summary>
/// 微信支付非同步通知驗證
/// </summary>
/// <param name="request">HTTP請求</param>
/// <param name="model">當驗證成功後,獲取主要返回引數</param>
/// <returns>驗證結果</returns>
bool VerifyNotify(HttpRequestBase request, out WePayReturnModel model);
}
}
Model
AliPayReturnModel.cs
namespace AW.Pay.Core.Model
{
public class AliPayReturnModel
{
/// <summary>
/// 商戶訂單號
/// </summary>
public string OutTradeNo { get; set; }
/// <summary>
/// 交易訂單號
/// </summary>
public string TradeNo { get; set; }
/// <summary>
/// 交易總金額
/// </summary>
public decimal TotalFee { get; set; }
/// <summary>
/// 交易狀態
/// </summary>
public string TradeStatus { get; set; }
}
}
WePayReturnModel.cs
namespace AW.Pay.Core.Model
{
public class WePayReturnModel
{
/// <summary>
/// 商戶訂單號
/// </summary>
public string OutTradeNo { get; set; }
/// <summary>
/// 交易訂單號
/// </summary>
public string TradeNo { get; set; }
/// <summary>
/// 交易金額(單位元)
/// </summary>
public decimal TotalFee { get; set; }
/// <summary>
/// 交易狀態
/// </summary>
public string TradeStatus { get; set; }
/// <summary>
/// 返回xml
/// </summary>
public string ReturnXml { get; set; }
}
}
類庫根目錄
AliPay.cs
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Web;
using AW.Pay.Core.Interface;
using AW.Pay.Core.Model;
namespace AW.Pay.Core
{
public class AliPay : IAlipay
{
public string BuildAliPay(string orderNo, string subject, decimal payAmount, EnumAliPayTradeType tradeType)
{
return BuildRequest(orderNo, subject, payAmount, tradeType);
}
public bool VerifyReturnURL(HttpRequestBase request, out AliPayReturnModel model)
{
var requestVal = request.QueryString;
return Verify(request, requestVal, out model);
}
public bool VerfyNotify(HttpRequestBase request, out AliPayReturnModel model)
{
var requestVal = request.Form;
return Verify(request, requestVal, out model);
}
#region private method
private bool Verify(HttpRequestBase request, NameValueCollection requestVal, out AliPayReturnModel model)
{
var result = false;
var sortedDic = new SortedDictionary<string, string>();
foreach (var item in requestVal.AllKeys)
{
if (item.ToLower() != "sign" && item.ToLower() != "sign_type" && !string.IsNullOrEmpty(item))
sortedDic.Add(item, requestVal[item]);
}
var requestSign = requestVal["sign"];
var requestSigntype = requestVal["sign_type"];
var param = CreateURLParamString(sortedDic);
var signType = requestSigntype == "MD5"
? EnumSignType.MD5
: requestSigntype == "RSA"
? EnumSignType.RSA
: EnumSignType.MD5;
if (signType == EnumSignType.MD5)
{
var sign = BuildRequestsign(param, signType);
if (requestSign.Equals(sign))
result = true;
}
else
result = RSAFromPkcs8.verify(param, requestSign, AlipayConfig.ALIPay_RSA_ALI_PUBLICKEY, "utf-8");
var responseText = GetResponseTxt(requestVal["notify_id"]);
var resultVal = result && responseText == "true";
if (resultVal)
{
model = new AliPayReturnModel
{
OutTradeNo = request.Form["out_trade_no"],
TradeNo = request.Form["trade_no"],
TradeStatus = request.Form["trade_status"]
};
decimal total_fee;
decimal.TryParse(request.Form["total_fee"], out total_fee);
model.TotalFee = total_fee;
}
else
model = null;
return resultVal;
}
private string BuildRequest(string orderNo, string subject, decimal totalAmt, EnumAliPayTradeType aliPayType)
{
var signType = aliPayType == EnumAliPayTradeType.APP ? EnumSignType.RSA : EnumSignType.MD5;
var dicParam = CreateParam(orderNo, subject, totalAmt, aliPayType);
var urlParam = CreateURLParamString(dicParam, aliPayType);
var sign = BuildRequestsign(urlParam, signType);
dicParam.Add("sign_type", signType.ToString());
if (aliPayType == EnumAliPayTradeType.APP)
{
//APP支付URL欄位須進行URL編碼,具體出處參看官方文件
sign = HttpUtility.UrlEncode(sign, Encoding.UTF8);
return urlParam + "&sign=\"" + sign + "\"&sign_type=\"" + signType + "\"";
}
dicParam.Add("sign", sign);
return BuildForm(dicParam);
}
private string BuildForm(SortedDictionary<string, string> dicParam)
{
var sbHtml = new StringBuilder();
sbHtml.Append("<form id='alipaysubmit' name='alipaysubmit' action='" + AlipayConfig.ALIPay_URL +
"_input_charset=" + AlipayConfig.CHARTSET + "' method='get'>");
foreach (var temp in dicParam)
{
sbHtml.Append("<input type='hidden' name='" + temp.Key + "' value='" + temp.Value + "'/>");
}
sbHtml.Append("<input type='submit' value='確認' style='display:none;'></form>");
sbHtml.Append("<script>document.forms['alipaysubmit'].submit();</script>");
return sbHtml.ToString();
}
private SortedDictionary<string, string> CreateParam(string orderNo, string subject, decimal totalAmt,
EnumAliPayTradeType aliPayType)
{
var dic = new SortedDictionary<string, string>();
#region BASEPARAM
var service = aliPayType == EnumAliPayTradeType.Website
? AlipayConfig.ALIPay_WEB_SERVICE
: aliPayType == EnumAliPayTradeType.Wap
? AlipayConfig.ALIPay_WAP_SERVICE
: aliPayType == EnumAliPayTradeType.APP
? AlipayConfig.ALIPay_MOBILE_SERVICE
: "";
dic.Add("service", service);
dic.Add("partner", AlipayConfig.ALI_PARTER);
dic.Add("_input_charset", AlipayConfig.CHARTSET);
dic.Add("notify_url", AlipayConfig.ALIPay_NotifyURL);
//dic.Add("sign_type", SIGNTYPE);
#endregion
#region BIZPARAM
dic.Add("out_trade_no", orderNo);
dic.Add("subject", subject);
dic.Add("payment_type", AlipayConfig.PAYMENT_TYPE);
dic.Add("total_fee", totalAmt.ToString("F2"));
//dic.Add("seller_email", ALI_SELLEREMAIL);
dic.Add("seller_id", AlipayConfig.ALI_SELLERID);
//dic.Add("anti_phishing_key", anti_phishing_key);//防釣魚時間戳,如果已申請開通防釣魚證,則此欄位必填。
//dic.Add("exter_invoke_ip", exter_invoke_ip);//客戶端 IP ,如果商戶申請後臺開通防釣魚 IP地址檢查選項,此欄位必填,校驗用。
#endregion
if (aliPayType == EnumAliPayTradeType.APP)
dic.Add("body", subject + "購買");
return dic;
}
private string CreateURLParamString(SortedDictionary<string, string> dicArray,
EnumAliPayTradeType type = EnumAliPayTradeType.Website)
{
var prestr = new StringBuilder();
foreach (var temp in dicArray.OrderBy(o => o.Key))
{
if (type == EnumAliPayTradeType.APP)
prestr.Append(temp.Key + "=\"" + temp.Value + "\"&");
else
prestr.Append(temp.Key + "=" + temp.Value + "&");
}
var nLen = prestr.Length;
prestr.Remove(nLen - 1, 1);
return prestr.ToString();
}
private string BuildRequestsign(string urlParam, EnumSignType signType)
{
var mysign = "";
if (signType == EnumSignType.MD5)
{
var preString = urlParam + AlipayConfig.ALI_KEY;
mysign = MD5Helper.Sign(preString, AlipayConfig.CHARTSET);
}
else if (signType == EnumSignType.RSA)
mysign = RSASign(urlParam, AlipayConfig.ALIPay_RSA_PRIVATEKEY, AlipayConfig.CHARTSET);
return mysign;
}
private string RSASign(string prestr, string privateKey, string input_charset)
{
try
{
return RSAFromPkcs8.sign(prestr, privateKey, input_charset);
}
catch (Exception e)
{
return e.Message;
}
}
private string GetResponseTxt(string notify_id)
{
var veryfy_url = AlipayConfig.ALI_HTTPS_VERYFY_URL + "&partner=" + AlipayConfig.ALI_PARTER + "¬ify_id=" +
notify_id;
var response = HTTPHelper.Get(veryfy_url, 120000);
return response;
}
#endregion
}
}
WePay.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Xml;
using AW.Pay.Core.Enum;
using AW.Pay.Core.Interface;
using AW.Pay.Core.Model;
using Newtonsoft.Json;
namespace AW.Pay.Core
{
public class WePay : IWePay
{
public string BuildWePay(string orderNo, string productName, int totalFee, string customerIP,
EnumWePayTradeType tradeType)
{
return UnifiedOrder(orderNo, productName, totalFee, customerIP, tradeType);
}
public bool VerifyNotify(HttpRequestBase request, out WePayReturnModel model)
{
var verifyResult = false;
model = new WePayReturnModel();
var requestXml = GetRequestXmlData(request);
var dic = FromXml(requestXml);
var returnCode = GetValueFromDic<string>(dic, "return_code");
if (!string.IsNullOrEmpty(returnCode) && returnCode == "SUCCESS") //通訊成功
{
var result = WePayNotifyValidation(dic);
if (result)
{
var transactionid = GetValueFromDic<string>(dic, "transaction_id");
if (!string.IsNullOrEmpty(transactionid))
{
var queryXml = BuildQueryRequest(transactionid, dic);
var queryResult = HTTPHelper.Post(WepayConfig.WEPAY_ORDERQUERY_URL, queryXml);
var queryReturnDic = FromXml(queryResult);
if (ValidatonQueryResult(queryReturnDic)) //查詢成功
{
verifyResult = true;
model.OutTradeNo = GetValueFromDic<string>(dic, "out_trade_no");
model.TotalFee = GetValueFromDic<decimal>(dic, "total_fee") / 100;
model.TradeNo = transactionid;
model.TradeStatus = GetValueFromDic<string>(dic, "result_code");
model.ReturnXml = BuildReturnXml("OK", "成功");
}
else
model.ReturnXml = BuildReturnXml("FAIL", "訂單查詢失敗");
}
else
model.ReturnXml = BuildReturnXml("FAIL", "支付結果中微信訂單號不存在");
}
else
model.ReturnXml = BuildReturnXml("FAIL", "簽名失敗");
}
else
{
string returnmsg;
dic.TryGetValue("return_msg", out returnmsg);
throw new Exception("非同步通知錯誤:" + returnmsg);
}
return verifyResult;
}
#region private method
/// <summary>
/// 統一下單
/// </summary>
/// <returns></returns>
private string UnifiedOrder(string orderNo, string productName, int totalFee, string customerIP,
EnumWePayTradeType tradeType)
{
var requestXml = BuildRequest(orderNo, productName, totalFee, customerIP, tradeType);
var resultXml = HTTPHelper.Post(WepayConfig.WEPAY_PAY_URL, requestXml);
var dic = FromXml(resultXml);
var returnCode = "";
dic.TryGetValue("return_code", out returnCode);
if (returnCode == "SUCCESS")
{
if (tradeType == EnumWePayTradeType.APP)
{
var prepay_id = GetValueFromDic<string>(dic, "prepay_id");
if (!string.IsNullOrEmpty(prepay_id))
return BuildAppPay(prepay_id);
throw new Exception("支付錯誤:" + GetValueFromDic<string>(dic, "err_code_des"));
}
if (tradeType == EnumWePayTradeType.NATIVE)
{
var codeUrl = "";
dic.TryGetValue("code_url", out codeUrl);
if (!string.IsNullOrEmpty(codeUrl))
return codeUrl;
throw new Exception("未找到對應的二維碼連結");
}
throw new Exception("JSAPI & WAP 未實現");
}
throw new Exception("後臺統一下單失敗");
}
private string BuildRequest(string orderNo, string productName, int totalFee, string customerIP,
EnumWePayTradeType tradeType)
{
var dicParam = CreateParam(orderNo, productName, totalFee, customerIP, tradeType);
var signString = CreateURLParamString(dicParam);
var key = tradeType == EnumWePayTradeType.APP ? WepayConfig.WEPAY_APP_KEY : WepayConfig.WEPAY_WEB_KEY;
var preString = signString + "&key=" + key;
var sign = MD5Helper.Sign(preString, WepayConfig.WEPAY_CHARTSET).ToUpper();
dicParam.Add("sign", sign);
return BuildForm(dicParam);
}
private static SortedDictionary<string, string> CreateParam(string orderNo, string productName, decimal totalFee,
string customerIP, EnumWePayTradeType tradeType)
{
var dic = new SortedDictionary<string, string>();
dic.Add("appid",
tradeType == EnumWePayTradeType.APP ? WepayConfig.WEPAY_APP_APPID : WepayConfig.WEPAY_WEB_APPID); //賬號ID
dic.Add("mch_id",
tradeType == EnumWePayTradeType.APP ? WepayConfig.WEPAY_APP_MCH_ID : WepayConfig.WEPAY_WEB_MCH_ID);
//商戶號
dic.Add("nonce_str", Guid.NewGuid().ToString().Replace("-", "")); //隨機字串
dic.Add("body", productName); //商品描述
dic.Add("out_trade_no", orderNo); //商戶訂單號
dic.Add("total_fee", totalFee.ToString()); //總金額
dic.Add("spbill_create_ip", customerIP); //終端IP
dic.Add("notify_url",
tradeType == EnumWePayTradeType.APP
? WepayConfig.WEPAY_APP_NOTIFY_URL
: WepayConfig.WEPAY_WEB_NOTIFY_URL); //通知地址
dic.Add("trade_type", tradeType.ToString()); //交易型別
return dic;
}
private static string CreateURLParamString(SortedDictionary<string, string> dicArray)
{
var prestr = new StringBuilder();
foreach (var temp in dicArray.OrderBy(o => o.Key))
{
prestr.Append(temp.Key + "=" + temp.Value + "&");
}
var nLen = prestr.Length;
prestr.Remove(nLen - 1, 1);
return prestr.ToString();
}
private static string BuildForm(SortedDictionary<string, string> dicParam)
{
var sbXML = new StringBuilder();
sbXML.Append("<xml>");
foreach (var temp in dicParam)
{
sbXML.Append("<" + temp.Key + ">" + temp.Value + "</" + temp.Key + ">");
}
sbXML.Append("</xml>");
return sbXML.ToString();
}
private static SortedDictionary<string, string> FromXml(string xml)
{
var sortDic = new SortedDictionary<string, string>();
if (string.IsNullOrEmpty(xml))
{
throw new Exception("將空的xml串轉換為WxPayData不合法!");
}
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
var xmlNode = xmlDoc.FirstChild; //獲取到根節點<xml>
var nodes = xmlNode.ChildNodes;
foreach (XmlNode xn in nodes)
{
var xe = (XmlElement)xn;
if (!sortDic.ContainsKey(xe.Name))
sortDic.Add(xe.Name, xe.InnerText);
}
return sortDic;
}
private static T GetValueFromDic<T>(SortedDictionary<string, string> dic, string key)
{
string val;
dic.TryGetValue(key, out val);
var returnVal = default(T);
if (val != null)
returnVal = (T)Convert.ChangeType(val, typeof(T));
return returnVal;
}
private static string BuildAppPay(string prepayid)
{
var dicParam = CreateWapAndAppPayParam(prepayid);
var signString = CreateURLParamString(dicParam);
var preString = signString + "&key=" + WepayConfig.WEPAY_APP_KEY;
var sign = MD5Helper.Sign(preString, WepayConfig.WEPAY_CHARTSET).ToUpper();
dicParam.Add("sign", sign);
return JsonConvert.SerializeObject(
new
{
appid = dicParam["appid"],
partnerid = dicParam["partnerid"],
prepayid = dicParam["prepayid"],
package = dicParam["package"],
noncestr = dicParam["noncestr"],
timestamp = dicParam["timestamp"],
sign = dicParam["sign"]
});
}
private static SortedDictionary<string, string> CreateWapAndAppPayParam(string prepayId)
{
var dic = new SortedDictionary<string, string>();
dic.Add("appid", WepayConfig.WEPAY_APP_APPID); //公眾賬號ID
dic.Add("partnerid", WepayConfig.WEPAY_APP_MCH_ID); //商戶號
dic.Add("prepayid", prepayId); //預支付交易會話ID
dic.Add("package", "Sign=WXPay"); //擴充套件欄位
dic.Add("noncestr", Guid.NewGuid().ToString().Replace("-", "")); //隨機字串
dic.Add("timestamp",
Convert.ToInt32((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds).ToString());
//時間戳
return dic;
}
private string GetRequestXmlData(HttpRequestBase request)
{
var stream = request.InputStream;
var count = 0;
var buffer = new byte[1024];
var builder = new StringBuilder();
while ((count = stream.Read(buffer, 0, 1024)) > 0)
{
builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
}
stream.Flush();
stream.Close();
stream.Dispose();
return builder.ToString();
}
public static bool WePayNotifyValidation(SortedDictionary<string, string> dic)
{
var sign = GetValueFromDic<string>(dic, "sign");
if (dic.ContainsKey("sign"))
{
dic.Remove("sign");
}
var tradeType = GetValueFromDic<string>(dic, "trade_type");
var preString = CreateURLParamString(dic);
if (string.IsNullOrEmpty(tradeType))
{
var key = tradeType == EnumWePayTradeType.APP.ToString()
? WepayConfig.WEPAY_APP_KEY
: WepayConfig.WEPAY_WEB_KEY;
var preSignString = preString + "&key=" + key;
var signString = MD5Helper.Sign(preSignString, WepayConfig.WEPAY_CHARTSET).ToUpper();
return signString == sign;
}
return false;
}
private static string BuildReturnXml(string code, string returnMsg)
{
return
string.Format(
"<xml><return_code><![CDATA[{0}]]></return_code><return_msg><![CDATA[{1}]]></return_msg></xml>",
code, returnMsg);
}
public static string BuildQueryRequest(string transactionId, SortedDictionary<string, string> dic)
{
var tradeType = GetValueFromDic<string>(dic, "trade_type");
var isApp = tradeType == EnumWePayTradeType.APP.ToString();
var dicParam = CreateQueryParam(transactionId, isApp);
var signString = CreateURLParamString(dicParam);
var key = isApp ? WepayConfig.WEPAY_APP_KEY : WepayConfig.WEPAY_WEB_KEY;
var preString = signString + "&key=" + key;
var sign = MD5Helper.Sign(preString, "utf-8").ToUpper();
dicParam.Add("sign", sign);
return BuildForm(dicParam);
}
private static SortedDictionary<string, string> CreateQueryParam(string transactionId, bool isApp)
{
var dic = new SortedDictionary<string, string>();
dic.Add("appid", isApp ? WepayConfig.WEPAY_APP_APPID : WepayConfig.WEPAY_WEB_APPID); //公眾賬號ID
dic.Add("mch_id", isApp ? WepayConfig.WEPAY_APP_MCH_ID : WepayConfig.WEPAY_WEB_MCH_ID); //商戶號
dic.Add("nonce_str", Guid.NewGuid().ToString().Replace("-", "")); //隨機字串
dic.Add("transaction_id", transactionId); //隨機字串
return dic;
}
private static bool ValidatonQueryResult(SortedDictionary<string, string> dic)
{
var result = false;
if (dic.ContainsKey("return_code") && dic.ContainsKey("return_code"))
{
if (dic["return_code"] == "SUCCESS" && dic["result_code"] == "SUCCESS")
result = true;
}
if (!result)
{
var sb = new StringBuilder();
foreach (var item in dic.Keys)
{
sb.Append(item + ":" + dic[item] + "|");
}
}
return result;
}
#endregion
}
}
App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<!--支付寶配置-->
<add key="ALIPay_URL" value="https://mapi.alipay.com/gateway.do?" />
<add key="ALIPay_NotifyURL" value="" />
<add key="ALIPay_ErrorURL" value="" />
<add key="ALI_PARTER" value="" />
<add key="ALI_KEY" value="" />
<add key="ALI_ACCOUNT" value="" />
<add key="ALI_SELLERID" value="" />
<add key="ALI_SELLEREMAIL" value="" />
<add key="ALI_HTTPS_VERYFY_URL" value="https://mapi.alipay.com/gateway.do?service=notify_verify" />
<add key="ALIPay_WAP_SERVICE" value="alipay.wap.create.direct.pay.by.user" />
<add key="ALIPay_WEB_SERVICE" value="create_direct_pay_by_user" />
<add key="ALIPay_MOBILE_SERVICE" value="mobile.securitypay.pay" />
<!--我的私鑰-->
<add key="ALIPay_RSA_PRIVATEKEY" value="" />
<!--我的公鑰-->
<add key="ALIPay_RSA_PUBLICKEY" value="" />
<!--支付寶公鑰-->
<add key="ALIPay_RSA_ALI_PUBLICKEY" value="" />
<!--微信支付配置-->
<add key="WEPAY_CHARTSET" value="utf-8" />
<add key="WEPAY_PAY_URL" value="https://api.mch.weixin.qq.com/pay/unifiedorder" />
<add key="WEPAY_ORDERQUERY_URL" value="https://api.mch.weixin.qq.com/pay/orderquery" />
<add key="WECHAT_AUTH_URL" value="https://open.weixin.qq.com/connect/oauth2/authorize" />
<add key="WECHAT_TOKEN_URL" value="https://api.weixin.qq.com/sns/oauth2/access_token" />
<add key="WECHAT_CALLBACKIP_URL" value="https://api.weixin.qq.com/cgi-bin/getcallbackip" />
<add key="WECHAT_GETTOKEN_URL" value="https://api.weixin.qq.com/cgi-bin/token" />
<!--開發者平臺配置-->
<add key="WEPAY_APP_APPID" value="" />
<add key="WEPAY_APP_MCH_ID" value="" />
<add key="WEPAY_APP_NOTIFY_URL" value="" />
<add key="WEPAY_APP_URL" value="" />
<add key="WEPAY_APP_KEY" value="" />
<!--公眾號平臺配置-->
<add key="WEPAY_WEB_APPID" value="" />
<add key="WEPAY_WEB_MCH_ID" value="" />
<add key="WEPAY_WEB_NOTIFY_URL" value="" />
<add key="WEPAY_WEB_URL" value="https://api.mch.weixin.qq.com/pay/unifiedorder" />
<add key="WEPAY_WEB_KEY" value="" />
</appSettings>
</configuration>
PaymentController.cs
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web.Mvc;
using AW.Pay.Core.Common;
using AW.Pay.Core.Enum;
using AW.Webapi.Sample.Models.PayModel;
namespace AW.Webapi.Sample.Controllers
{
public class PaymentController : Controller
{
public static HttpClient _client = new HttpClient();
// GET: Payment
public ActionResult Index()
{
return View();
}
public ActionResult AliPayDemo()
{
return View();
}
public async Task<string> AliPayAsync(AliPayReqParam payInfo)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:8115/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP POST
var gizmo = new AliPayReqParam
{
OrderNo = payInfo.OrderNo,
Subject = payInfo.Subject,
TotalAmount = payInfo.TotalAmount,
Type = 0
};
var response = await client.PostAsJsonAsync("api/Payment/CreateAliPayRequestParam", gizmo);
var resultValue = await response.Content.ReadAsAsync<BizResult<string>>();
if (resultValue.Code == EnumBizCode.Failed)
{
return string.Empty;
}
return resultValue.ReturnObject;
}
}
public ActionResult WePayDemo()
{
return View();
}
public async Task<ActionResult> WePayAsync(WePayReqParam payInfo)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:8115/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP POST
var gizmo = new WePayReqParam
{
OrderNo = payInfo.OrderNo,
ProductName = payInfo.ProductName,
CustomerIp = "127.0.0.1",
TotalFee = payInfo.TotalFee,
TradeType = EnumWePayTradeType.NATIVE
};
var response = await client.PostAsJsonAsync("api/Payment/CreateWePayRequestParam", gizmo);
var resultValue = await response.Content.ReadAsAsync<BizResult<string>>();
if (resultValue.Code == EnumBizCode.Failed)
{
throw new Exception("微信支付失敗");
}
ViewBag.OrderId = payInfo.OrderNo;
ViewBag.PayAmount = payInfo.TotalFee;
ViewBag.PayUrl = resultValue.ReturnObject;
return View("WePay");
}
}
}
}
WePayDemo.cshtml
@model AW.Webapi.Sample.Models.PayModel.WePayReqParam
@{
ViewBag.Title = "WePayDemo";
}
<h2>WePayDemo</h2>
@using (Html.BeginForm("WePayAsync", "Payment", FormMethod.Get))
{
<div class="form-horizontal">
<h4>WePayReqParam</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.OrderNo, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.OrderNo, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.OrderNo, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProductName, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProductName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProductName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.TotalFee, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.TotalFee, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.TotalFee, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
WePay.cshtml
@{
ViewBag.Title = "WePayAsync";
}
<h2>WePayAsync</h2>
<input type="hidden" id="hd_url" value="@ViewBag.PayUrl">
<input type="hidden" value="@ViewBag.OrderId" id="hd_order_id"/>
<div class="weixin-img">
</div>
@section scripts{
<script src="~/Scripts/jquery.qrcode.min.js"></script>
<script>
var weiPay = $('#hd_url').val();
$('.weixin-img').qrcode({
render: "canvas", //table方式
text: weiPay //任意內容
});
</script>
}
Areas\Api\Controllers\PaymentController.cs
using System.Web;
using System.Web.Http;
using AW.Pay.Core.Common;
using AW.Pay.Core.Interface;
using AW.Pay.Core.Model;
using AW.Webapi.Sample.Models.PayModel;
namespace AW.Webapi.Sample.Areas.Api.Controllers
{
public class PaymentController : ApiController
{
private readonly IAlipay _aliPay;
private readonly IWePay _wePay;
public PaymentController(IAlipay aliPay, IWePay wePay)
{
_aliPay = aliPay;
_wePay = wePay;
}
/// <summary>
/// 生成支付寶請求引數
/// </summary>
/// <param name="payInfo"></param>
/// <returns></returns>
[HttpPost]
public BizResult<string> CreateAliPayRequestParam(AliPayReqParam payInfo)
{
var biz = new BizResult<string>();
biz.ReturnObject = _aliPay.BuildAliPay(payInfo.OrderNo, payInfo.Subject, payInfo.TotalAmount, payInfo.Type);
;
return biz;
}
/// <summary>
/// 支付寶支付結果非同步通知
/// </summary>
/// <returns>Form表單</returns>
[HttpPost]
public void AlipayNotify()
{
var payResult = new AliPayReturnModel();
var context = (HttpContextBase)Request.Properties["MS_HttpContext"]; //獲取傳統context
var request = context.Request; //定義傳統request物件
var result = _aliPay.VerfyNotify(request, out payResult);
}
/// <summary>
/// 生成支付寶請求引數
/// </summary>
/// <param name="payInfo"></param>
/// <returns></returns>
[HttpPost]
public BizResult<string> CreateWePayRequestParam(WePayReqParam payInfo)
{
var biz = new BizResult<string>();
biz.ReturnObject = _wePay.BuildWePay(payInfo.OrderNo, payInfo.ProductName, payInfo.TotalFee,
payInfo.CustomerIp, payInfo.TradeType);
;
return biz;
}
/// <summary>
/// 微信支付支付結果非同步通知
/// </summary>
/// <returns></returns>
[HttpPost]
public void WePayNotify()
{
var payResult = new WePayReturnModel();
var context = (HttpContextBase)Request.Properties["MS_HttpContext"]; //獲取傳統context
var request = context.Request; //定義傳統request物件
var result = _wePay.VerifyNotify(request, out payResult);
}
}
}
PayModel
AliPayReqParam.cs
using AW.Pay.Core;
namespace AW.Webapi.Sample.Models.PayModel
{
public class AliPayReqParam
{
public string OrderNo { get; set; }
public string Subject { get; set; }
public decimal TotalAmount { get; set; }
public EnumAliPayTradeType Type { get; set; }
}
}
WePayReqParam.cs
using AW.Pay.Core.Enum;
namespace AW.Webapi.Sample.Models.PayModel
{
public class WePayReqParam
{
public string OrderNo { get; set; }
public string ProductName { get; set; }
public int TotalFee { get; set; }
public string CustomerIp { get; set; }
public EnumWePayTradeType TradeType { get; set; }
}
}
Bootstrapper.cs
using System.Reflection;
using System.Web.Http;
using System.Web.Mvc;
using Autofac;
using Autofac.Integration.Mvc;
using Autofac.Integration.WebApi;
using AW.Pay.Core;
using AW.Pay.Core.Interface;
namespace AW.Webapi.Sample.App_Start
{
public class Bootstrapper
{
public static void Run()
{
SetAutoFacContainer();
}
private static void SetAutoFacContainer()
{
var builder = new ContainerBuilder();
//Get HttpConfiguration
var config = GlobalConfiguration.Configuration;
//Register MVC Controller
builder.RegisterControllers(Assembly.GetExecutingAssembly());
//Register Web Api Controller
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
//Register Pay Interface
builder.RegisterType<AliPay>().As<IAlipay>().InstancePerRequest();
builder.RegisterType<WePay>().As<IWePay>().InstancePerRequest();
//Set the dependency resolver to be Autofac
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container); //Web Api
DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); //MVC
}
}
}
Global.asax
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using AW.Webapi.Sample.App_Start;
namespace AW.Webapi.Sample
{
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Bootstrapper.Run();
}
}
}
Web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework"
type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</configSections>
<connectionStrings>
<add name="DefaultConnection"
connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-AW.Webapi.Sample-20160201054737.mdf;Initial Catalog=aspnet-AW.Webapi.Sample-20160201054737;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<appSettings>
<!--支付寶配置-->
<add key="ALIPay_URL" value="https://mapi.alipay.com/gateway.do?" />
<add key="ALIPay_NotifyURL" value="" />
<add key="ALIPay_ErrorURL" value="" />
<add key="ALI_PARTER" value="" />
<add key="ALI_KEY" value="" />
<add key="ALI_ACCOUNT" value="" />
<add key="ALI_SELLERID" value="" />
<add key="ALI_SELLEREMAIL" value="" />
<add key="ALI_HTTPS_VERYFY_URL" value="https://mapi.alipay.com/gateway.do?service=notify_verify" />
<add key="ALIPay_WAP_SERVICE" value="alipay.wap.create.direct.pay.by.user" />
<add key="ALIPay_WEB_SERVICE" value="create_direct_pay_by_user" />
<add key="ALIPay_MOBILE_SERVICE" value="mobile.securitypay.pay" />
<!--我的私鑰-->
<add key="ALIPay_RSA_PRIVATEKEY" value="" />
<!--我的公鑰-->
<add key="ALIPay_RSA_PUBLICKEY" value="" />
<!--支付寶公鑰-->
<add key="ALIPay_RSA_ALI_PUBLICKEY" value="" />
<!--微信支付配置-->
<add key="WEPAY_CHARTSET" value="utf-8" />
<add key="WEPAY_PAY_URL" value="https://api.mch.weixin.qq.com/pay/unifiedorder" />
<add key="WEPAY_ORDERQUERY_URL" value="https://api.mch.weixin.qq.com/pay/orderquery" />
<add key="WECHAT_AUTH_URL" value="https://open.weixin.qq.com/connect/oauth2/authorize" />
<add key="WECHAT_TOKEN_URL" value="https://api.weixin.qq.com/sns/oauth2/access_token" />
<add key="WECHAT_CALLBACKIP_URL" value="https://api.weixin.qq.com/cgi-bin/getcallbackip" />
<add key="WECHAT_GETTOKEN_URL" value="https://api.weixin.qq.com/cgi-bin/token" />
<!--開發者平臺配置-->
<add key="WEPAY_APP_APPID" value="" />
<add key="WEPAY_APP_MCH_ID" value="" />
<add key="WEPAY_APP_NOTIFY_URL" value="" />
<add key="WEPAY_APP_URL" value="" />
<add key="WEPAY_APP_KEY" value="" />
<!--公眾號平臺配置-->
<add key="WEPAY_WEB_APPID" value="" />
<add key="WEPAY_WEB_MCH_ID" value="" />
<add key="WEPAY_WEB_NOTIFY_URL" value="" />
<add key="WEPAY_WEB_URL" value="https://api.mch.weixin.qq.com/pay/unifiedorder" />
<add key="WEPAY_WEB_KEY" value="" />
</appSettings>
<system.web>
<authentication mode="None" />
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6.1" />
</system.web>
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*"
type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Autofac" publicKeyToken="17863af14b0044da" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.5.0.0" newVersion="3.5.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient"
type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs"
type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
warningLevel="4"
compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\"Web\" /optionInfer+" />
</compilers>
</system.codedom>
</configuration>
相關文章
- 微信支付,支付寶支付
- 關於微信支付,支付寶支付
- 支付寶微信合單支付
- PHP-Laravel支付寶支付和微信支付PHPLaravel
- 微信、支付寶支付那點事
- Laravel 搞定支付寶和微信掃碼支付Laravel
- 關於支付寶以及微信支付的整合
- Python提取支付寶和微信支付二維碼Python
- android 整合微信支付和支付寶支付其實很簡單Android
- java實現沙箱測試環境支付寶支付(demo)和整合微信支付和支付寶支付到springmvc+spring+mybatis環境全過程(支付寶和微信支付、附原始碼)JavaSpringMVCMyBatis原始碼
- XorPay 個人支付平臺【支援個人微信支付和支付寶支付介面】
- 使用 yansongda/pay 進行支付寶和微信 App 支付APP
- Android 接入微信支付寶支付Android
- pay-spring-boot 開箱即用的Java支付模組,整合支付寶支付、微信支付SpringbootJava
- 支付寶、微信支付收款碼禁止商用系誤讀NL
- mui 判斷手機客戶端是否安裝微信或支付寶或淘寶等,mui 獲取微信、支付寶支付通道UI客戶端
- 對iOS端支付寶和微信支付程式碼進行整合iOS
- 微信發支付寶紅包(花唄)
- 移動支付新時代——低程式碼如何對接支付寶和微信支付
- 微信掃碼支付(Asp.Net MVC)ASP.NETMVC
- Epic港服開通支付寶、微信支付 更方便買遊戲遊戲
- 微信和支付寶的支付流程,以及開發中遇到的坑?
- 關於建行龍支付的聚合支付微信,支付寶 對接PC和H5H5
- 在App中對接微信和支付寶APP
- 支付寶小程式對比微信小程式微信小程式
- 微信,支付寶小程式實現原理概述
- 面試集錦(十)支付寶與微信面試
- nodejs微信支付之掃碼支付NodeJS
- 微信JSAPI支付JSAPI
- 微信App支付APP
- 支付寶支付
- 個人開發者福音,輕鬆接入個人簽約微信支付、支付寶支付妙招
- 網際網路新貴向支付寶、微信支付發起挑戰
- JAVA版微信支付V3—JSAPI支付JavaJSAPI
- 支付寶,微信,充值遇到的到賬延遲
- 微信支付團隊釋出“微信青蛙pro” 支援刷臉支付功能
- 微信開發超市全反系統,微信支付刷卡支付,微信介面簡單配置!
- MaxAI-國內使用者可以嘗試使用支付寶或微信支付使用GPT。AIGPT