.NET微信掃碼支付接入(模式二-NATIVE)
一、前言
經(jīng)過兩三天的琢磨總算完成了微信掃碼支付功能,不得不感嘆幾句:
微信提供的DEMO不錯(cuò),直接復(fù)制粘貼就可以跑起來了;
微信的配置平臺(tái)我真是服了。公眾平臺(tái)、商戶平臺(tái)、開放平臺(tái),一個(gè)平臺(tái)一套賬戶密碼,大寫的惡心
DEMO地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1
.NET版DEMO中的Lib文件夾是關(guān)鍵,直接復(fù)制到自己的代碼里,或者打成dll隨個(gè)人意愿。
二、正文
Step1:肯定是產(chǎn)生商戶訂單號(hào),然后傳給微信后臺(tái),由微信去組成二維碼字符串,然后返給你,你再把字符串做成圖片;
/// <summary>
/// 獲取二維碼
/// </summary>
/// <param name="orderNumber"></param>
/// <returns></returns>
public string GetCodeUrl(string orderNumber)
{
var result = string.Empty;
if (!string.IsNullOrEmpty(orderNumber))
{
var matchedItem = db.OrderInfoForProducts.FirstOrDefault(x => x.OrderNumber == orderNumber);
if (matchedItem != null && matchedItem.IsPaid == false)
{
WxPayData data = new WxPayData();
data.SetValue("body", "productBody");//商品描述
data.SetValue("attach", "attach data");//附加數(shù)據(jù)
data.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());//隨機(jī)字符串
data.SetValue("total_fee", price);//總金額
data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));//交易起始時(shí)間
data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));//交易結(jié)束時(shí)間
data.SetValue("goods_tag", "tag");//商品標(biāo)記
data.SetValue("trade_type", "NATIVE");//交易類型
data.SetValue("product_id", WxPayApi.GenerateOutTradeNo());//商品ID
result = WxPayApi.UnifiedOrder(data).GetValue("code_url").ToString();//調(diào)用統(tǒng)一下單接口
}
}
return result;
}
在這里,我是把公司的商戶訂單號(hào)放在了attach字段上,因?yàn)楣镜纳虘粲唵翁?hào)比較長,超過了32位。out_trade_no與product_id字段最多32位,請(qǐng)慎重!
微信中的價(jià)格不能帶小數(shù),所以0.01元要寫成100。
Step2: 成功返回二維碼字符串之后就可以在生成圖片了,我這邊使用了ThoughtWorks.QRCode.dll來生成圖片:
/// <summary>
/// 根據(jù)字符串得到相應(yīng)的二維碼
/// </summary>
/// <param name="qrInfo"></param>
/// <param name="productName"></param>
/// <param name="version"></param>
/// <returns></returns>
public static Image CreateQRCodeImage(string qrInfo, string productName, string version)
{
try
{
if (!string.IsNullOrEmpty(qrInfo))
{
QRCodeEncoder encoder = new QRCodeEncoder
{
QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE,
QRCodeScale = 4,
QRCodeVersion = 0,
QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M
};
//編碼方式(注意:BYTE能支持中文,ALPHA_NUMERIC掃描出來的都是數(shù)字)
//大小(值越大生成的二維碼圖片像素越高)
//版本(注意:設(shè)置為0主要是防止編碼的字符串太長時(shí)發(fā)生錯(cuò)誤)
//錯(cuò)誤效驗(yàn)、錯(cuò)誤更正(有4個(gè)等級(jí))
Image image = encoder.Encode(qrInfo, Encoding.GetEncoding("utf-8"));
string filename = $"{productName}_{version}.png";
var userLocalPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var docPath = Path.Combine(userLocalPath, @"Your Product\QRCode");
if (!Directory.Exists(docPath))
{
Directory.CreateDirectory(docPath);
}
string filepath = Path.Combine(docPath, filename);
using (FileStream fs = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write))
{
image.Save(fs, System.Drawing.Imaging.ImageFormat.Png);
fs.Close();
image.Dispose();
}
return image;
}
}
catch (Exception)
{
return null;
}
return null;
}
Step3: 當(dāng)用戶掃完二維碼之后,微信會(huì)發(fā)起回調(diào),這時(shí)候我們就可以處理自己的業(yè)務(wù)邏輯了。這里我的UpdatePayStatus返回的是一個(gè)空頁面
/// <summary>
/// 回調(diào)函數(shù)
/// </summary>
public ActionResult UpdatePayStatus()
{
//接收從微信后臺(tái)POST過來的數(shù)據(jù)
System.IO.Stream s = Request.InputStream;
int count = 0;
byte[] buffer = new byte[1024];
StringBuilder builder = new StringBuilder();
while ((count = s.Read(buffer, 0, 1024)) > 0)
{
builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
}
s.Flush();
s.Close();
s.Dispose();
//轉(zhuǎn)換數(shù)據(jù)格式并驗(yàn)證簽名
WxPayData data = new WxPayData();
try
{
data.FromXml(builder.ToString());
}
catch (WxPayException ex)
{
//若簽名錯(cuò)誤,則立即返回結(jié)果給微信支付后臺(tái)
WxPayData res = new WxPayData();
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", ex.Message);
LogEntity signErrorLog = new LogEntity();
signErrorLog.errorMessage = ex.Message;
LogHelper.WriteLog(signErrorLog, null);
Response.Write(res.ToXml());
Response.End();
}
ProcessNotify(data);
return View();
}
/// <summary>
/// 處理回調(diào)數(shù)據(jù)
/// </summary>
/// <param name="data"></param>
public void ProcessNotify(WxPayData data)
{
WxPayData notifyData = data;
//檢查支付結(jié)果中transaction_id是否存在
if (!notifyData.IsSet("transaction_id"))
{
//若transaction_id不存在,則立即返回結(jié)果給微信支付后臺(tái)
WxPayData res = new WxPayData();
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", "支付結(jié)果中微信訂單號(hào)不存在");
LogEntity orderLog = new LogEntity();
orderLog.errorMessage = "支付結(jié)果中微信訂單號(hào)不存在";
LogHelper.WriteLog(orderLog, null);
Response.Write(res.ToXml());
Response.End();
}
string transaction_id = notifyData.GetValue("transaction_id").ToString();
//查詢訂單,判斷訂單真實(shí)性
if (!QueryOrder(transaction_id))
{
//若訂單查詢失敗,則立即返回結(jié)果給微信支付后臺(tái)
WxPayData res = new WxPayData();
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", "訂單查詢失敗");
LogEntity orderqueryLog = new LogEntity();
orderqueryLog.errorMessage = "訂單查詢失敗";
LogHelper.WriteLog(orderqueryLog, null);
Response.Write(res.ToXml());
Response.End();
}
//查詢訂單成功
else
{
WxPayData res = new WxPayData();
res.SetValue("return_code", "SUCCESS");
res.SetValue("return_msg", "OK");
SetPaymentResult(data); //這里的參數(shù)是 data ?。。?不是 res ?。?!
Response.Write(res.ToXml());
Response.End();
}
}
/// <summary>
/// 商戶后臺(tái)更新
/// </summary>
/// <param name="res"></param>
private void SetPaymentResult(WxPayData res)
{
var isSucessFlagOne = res.GetValue("return_code").ToString();
var isSuccessFlagTwo = res.GetValue("result_code").ToString();
if (isSucessFlagOne == "SUCCESS" && isSuccessFlagTwo == "SUCCESS")
{
//自己的業(yè)務(wù)邏輯 ?。。?!
}
}
//查詢訂單
private bool QueryOrder(string transaction_id)
{
WxPayData req = new WxPayData();
req.SetValue("transaction_id", transaction_id);
WxPayData res = WxPayApi.OrderQuery(req);
if (res.GetValue("return_code").ToString() == "SUCCESS" &&
res.GetValue("result_code").ToString() == "SUCCESS")
{
return true;
}
else
{
return false;
}
}
三、結(jié)尾
做完支付寶與微信掃碼支付發(fā)現(xiàn)支付寶的接入要比微信方便很多,還有一個(gè)同步請(qǐng)求。而且吐槽個(gè)其它的,微信開放平臺(tái)的審批速度要比支付寶的審批慢很多。還有微信支付最后上線前不需要非得用沙箱測試,做完之后直接一分錢一分錢測試即可。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Entity?Framework實(shí)現(xiàn)數(shù)據(jù)遷移
本文詳細(xì)講解了Entity?Framework實(shí)現(xiàn)數(shù)據(jù)遷移的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03
Web API中使用Autofac實(shí)現(xiàn)依賴注入
本文詳細(xì)講解了Web API中使用Autofac實(shí)現(xiàn)依賴注入的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03
Redis數(shù)據(jù)庫基礎(chǔ)與ASP.NET?Core緩存實(shí)現(xiàn)
這篇文章介紹了Redis數(shù)據(jù)庫基礎(chǔ)與ASP.NET?Core緩存實(shí)現(xiàn)的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02
ASP.NET Core3.1 Ocelot負(fù)載均衡的實(shí)現(xiàn)
這篇文章主要介紹了ASP.NET Core3.1 Ocelot負(fù)載均衡的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
ASP.NET GridView中文本內(nèi)容無法換行(自動(dòng)換行/正常換行)
用GridView來顯示課程表,每個(gè)單元格的內(nèi)容包括課程名、上課地點(diǎn)、教師姓名,然后我想讓它們分行顯示,感興趣的朋友可以了解下,或許對(duì)你有所幫助2013-02-02
Visual Studio 2017 (VS 2017)離線安裝包制作方法
這篇文章主要為大家詳細(xì)介紹了Visual Studio 2017離線安裝包的制作方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03

