I. Preface
Recently, blogs have been updating slowly because they are busy with new products. In order to facilitate users to pay, new products need Alipay scan code access. It fell to me. The product is desktop software under Windows system, which generates two-dimensional code payment through software. The interface is written in native MVVM. The following is a description of the basic process. The old driver who has done it can turn it off directly.
II. Application Interface
The first step is to apply for an interface.
- The company has Alipay account.
- The company has business qualifications (nonsense)
- Create applications, sign computer website payment, mobile payment, App payment.
- Create private key, public key, Alipay public key
- Configure Gateway and Callback Address
Attention should be paid to the following points:
- When creating an application, do not use the words "pay" or "pay" in the name. The picture suggests HD.
- When creating applications, contract payment requires some application materials, such as: business qualification photos, company photos 4, application introduction (name, download address, whether the company website has the application, the application has Alipay payment interface style).
- After signing the contract, it needs to be audited for about one day (Ali really fast, Tencent Weixin takes 4 days). After the approval, an email will be sent, which contains a link, click on the link to complete the signing.
- Create a private key, a public key, and a Alipay public key. There is an official tool on the Alipay interface website to download and use.
- Gateway and callback address should be associated with company website, such as secondary domain name; if gateway and callback address have no connection with company website, I am afraid not.
3. Code flow
There are three components. Client software, merchant server background, Alipay backstage
Client software clicks "Get Payment Two-Dimensional Code" to get a Payable Two-Dimensional Code:
Encapsulating some necessary information from the client and sending it back to the merchant server to form a merchant order
/// <summary> /// Obtaining Two-Dimensional Code Information /// </summary> /// <param name="packageClientInfo">Packaging information</param> /// <param name="serverAddress">Merchant Product Server Address</param> /// <returns></returns> public static void GetQRCodeInfo(string packageClientInfo, string serverAddress, Action<string> getQRCodeAction) { if (!string.IsNullOrEmpty(packageClientInfo)) { try { HttpClient httpsClient = new HttpClient { BaseAddress = new Uri(serverAddress), Timeout = TimeSpan.FromMinutes(20) }; if (DsClientOperation.ConnectionTest(httpsClient)) { StringContent strData = new StringContent( packageClientInfo, Encoding.UTF8, RcCommonNames.JasonMediaType); string PostUrl = httpsClient.BaseAddress + "api/AlipayForProduct/GetQRCodeString"; Uri address = new Uri(PostUrl); Task<HttpResponseMessage> response = httpsClient.PostAsync(address, strData); response.ContinueWith( (postTask) => { if (postTask.IsFaulted) { throw postTask.Exception; } HttpResponseMessage postResponse = postTask.Result; postResponse.EnsureSuccessStatusCode(); var result = postResponse.Content.ReadAsStringAsync().Result; getQRCodeAction(JsonConvert.DeserializeObject<string>(result)); //Pay attention to this Commission return result; }); } } catch { // ignored } } }
The delegation method here is used to generate two-dimensional codes, when you return some strings (result s) from this "api/AlipayForProduct/GetQRCodeString", for example:
"Http://xxx.xxx.com/AlipayForProduct/SendInfoToAlipay?Ordernumber="+$"{orderNumber}"; (orderNumber is the merchant order number)
ThoughtWorks.QRCode.dll is then used to generate two-dimensional codes.
/// <summary> /// Get the corresponding two-dimensional code from the string /// </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 }; //Coding mode(Be careful: BYTE Can support Chinese, ALPHA_NUMERIC The scans are all numbers.) //Size(The bigger the value, the higher the pixel of the two-dimensional code picture) //Edition(Note: Setting to 0 prevents errors when encoding strings too long) //Error Effect, Error Correction(There are four levels) 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, @"YourProduct\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; }
In this way, a two-dimensional code is generated. In other words, the api of a service is changed from a string into a picture. When the user uses Alipay app to sweep the two-dimensional code, it will ask the api:
"Http://xxx.xxx.com/AlipayForProduct/SendInfoToAlipay? Order number="+$"{orderNumber}"; (orderNumber is the merchant order number)
public string SendInfoToAlipay() { string orderNumber = Request["orderNumber"]; if (!string.IsNullOrEmpty(orderNumber)) { var matchedItem = db.OrderInfoForProduct.FirstOrDefault(x => x.OrderNumber == orderNumber); //Verify that the merchant server backend has this order if (matchedItem != null && matchedItem.IsPaid == false) { //Common parameter var alipayServerURL = "https://openapi.alipay.com/gateway.do"; var app_id = appID; var privateKeyPem = applicationPrivateKey; var format = "json"; var version = "1.0"; var signType = "RSA2"; //Request parameters var out_trade_no = orderNumber; //Merchant Order Number var product_code = "FAST_INSTANT_TRADE_PAY"; //Sales product code var total_amount = "Your Money"; //Total order amount var subject = "Your Title"; //Order title var body = "Your Body"; //Order description IAopClient client = new DefaultAopClient( alipayServerURL, app_id, privateKeyPem, format, version, signType); var returnurl = $"http://xxx.xxx.com/AlipayForProduct/AlipayResult"; var notifyurl = $"http://xxx.xxx.com/AlipayForProduct/UpdatePayStatus";
AlipayTradeWapPayRequest requestWap = new AlipayTradeWapPayRequest { BizContent = "{" + " \"body\":\"" + body + "\"," + " \"subject\":\"" + subject + "\"," + " \"out_trade_no\":\"" + out_trade_no + "\"," + " \"total_amount\":" + total_amount + "," + " \"product_code\":\"" + product_code + "\"" + " }" }; requestWap.SetNotifyUrl(notifyurl); //Asynchronous request requestWap.SetReturnUrl(returnurl); //Synchronous request AlipayTradeWapPayResponse responseWap = client.pageExecute(requestWap); string divNone = "<div style='display:none'>" + responseWap.Body + "</div>"; return divNone; } } return string.Empty; }
Asynchronous requests generally need to do a few things:
- After the user scan code is paid, the background information of Alipay will send you all the information you need to verify, except that one parameter does not need to be signed, and the rest needs to be checked.
- If the signature is successful and the payment status is also successful, you need to update the status of the merchant server background about this merchant order, such as changing its payment status to paid, filling the payment time, etc.
/// <summary> /// callback /// </summary> [HttpPost] public void UpdatePayStatus() { SortedDictionary<string, string> sPara = GetRequestPost(); if (sPara.Count > 0) { //Non-checking parameters var sign_type = Request.Form["sign_type"]; //Receive parameters and sort them var seller_id = Request.Form["seller_id"]; //Seller Alipay user number var trade_status = Request.Form["trade_status"]; //Trading status var notify_time = Request.Form["notify_time"]; //Notification time var app_id = Request.Form["app_id"]; //developer AppId var out_trade_no = Request.Form["out_trade_no"]; //Transaction Order Number var total_amount = Request.Form["total_amount"]; //Order amount var receipt_amount = Request.Form["receipt_amount"]; //Amount received var invoice_amount = Request.Form["invoice_amount"]; //Amount of invoice var buyer_pay_amount = Request.Form["buyer_pay_amount"]; //Payment amount var body = Request.Form["body"]; //Commodity Description var gmt_payment = Request.Form["gmt_payment"]; //Transaction Payment Time var tradeGuid = new Guid(out_trade_no); //Check sign try { var isVerfied = AlipaySignature.RSACheckV1(sPara, alipayPublicKey, "utf-8", sign_type, false); if (isVerfied) { if (app_id == appID && seller_id == sellerID) { var isTradeSuccess = string.Equals(trade_status, "TRADE_SUCCESS") || string.Equals(trade_status, "TRADE_FINISHED"); if (isTradeSuccess) { //Business Verification Logic and Data Update Logic } } } } catch (Exception) { } } else { } }
/// <summary>
/// Parametric Sorting Dictionary
/// </summary>
/// <returns></returns>
private SortedDictionary<string, string> GetRequestPost()
{
SortedDictionary<string, string> sArray = new SortedDictionary<string, string>();
NameValueCollection coll = Request.Form;
String[] requestItem = coll.AllKeys;
foreach (string t in requestItem)
{
sArray.Add(t, Request.Form[t]);
}
return sArray;
}
Synchronization requests typically require several things:
1. When the asynchronous call is completed, if the payment is successful and the order number is processed correctly by the merchant server background, the synchronous request can be validated again.
2. If the verification is successful, jump the Payment Success Page; if it fails, jump the Payment Failure Page.
public ActionResult AlipayResult() { SortedDictionary<string, string> sPara = GetRequestGet(); if (sPara.Count > 0) { //Non-checking parameters var sign_type = Request.QueryString["sign_type"]; //Receive parameters and sort them var seller_id = Request.QueryString["seller_id"]; //Seller Alipay user number var app_id = Request.QueryString["app_id"]; //developer AppId var out_trade_no = Request.QueryString["out_trade_no"]; //Transaction Order Number var orderNumberGuid = new Guid(out_trade_no); try { var isVerfied = AlipaySignature.RSACheckV1(sPara, alipayPublicKey, "utf-8", sign_type, false); if (isVerfied) { if (app_id == appID && seller_id == sellerID) { //Your Payment Success Page } } } catch { //Your Payment Failure Page } } else { //Your Payment Failure Page } return View(); } /// <summary> /// Parametric Sorting Dictionary /// </summary> /// <returns></returns> private SortedDictionary<string, string> GetRequestGet() { SortedDictionary<string, string> sArray = new SortedDictionary<string, string>(); NameValueCollection coll = Request.QueryString; String[] requestItem = coll.AllKeys; foreach (string t in requestItem) { sArray.Add(t, Request.QueryString[t]); } return sArray; }
Four, ending
WPF has been my major since I joined the work. It's interesting to do the Web occasionally.