.Net WeChat Computer Website Payment (api v2)

When merchants or enterprises go to the open platform of WeChat to apply for WeChat payment, it is important to note that the payment function of WeChat is not open to individual users. After opening the payment function, they will get the following configuration information about WeChat payment:

  • Appid: is the unique identification of WeChat public account or Open Platform APP. After applying for public account on the public platform or App account on the open platform, WeChat automatically assigns the corresponding appid to identify the application.
  • mch_id: After a merchant applies for WeChat payment, the account allocated by WeChat will be paid.
  • Key: The key used by the transaction to generate the signature can be accessed at: WeChat Merchant Platform (pay.weixin.qq.com) - Account Center - Account Settings - API Security - Key Settings
  • Appsecret: AppSecret is the interface password corresponding to APPID, which is used to get the interface invocation credential access_token, and does not participate in the WeChat payment process.

1. Payment process

II. Agreement Rules

When using the WeChat API interface, the following rules must be followed:

  • Transport mode: HTTPS transmission is used to ensure transaction security
  • Submit method: Submit using POST method
  • Data format: Both submitted and returned data are in XML format, and the root node is named XML
  • Character encoding: WeChat payment API v2 only supports UTF-8 character encoding.
  • Signature algorithm: MD5/HMAC-SHA256

3. Signature algorithm

The WeChat payment uses MD5/HMAC-SHA256 to sign and verify the data.
First, all sent or accepted non-empty data is concatenated into strings in the form of URL key-value pairs (key1=value1&key2=value2), ASCII codes as parameter names are sorted from smallest to largest (dictionary order), then keys used for WeChat signatures are concatenated at the end, and then signature values are obtained using MD5/HMAC-SHA256 pairs of string signatures.

  • Parameters must be sorted from smallest to largest ASCII codes.
  • Null parameter does not participate in signing.
  • Parameter names are case sensitive.
  • The sign parameter does not participate in the signature when verifying the reconciliation signature. The generated signature is checked against the sign value.

Four Asynchronous Notifications

When the WeChat background payment succeeds, it calls the asynchronous notification interface of the merchant background and sends the payment result to the merchant background. The merchant background processes the business platform logic based on the payment result obtained. Some points should be noted when processing:

  • The same asynchronous notification WeChat may be sent multiple times. Data locks must be used for concurrency control to avoid data clutter.
  • When dealing with a notification in the business background, you need to first determine if the notification has been successfully processed. If the processing is successful, return the success information directly.
  • The WeChat background does not receive the success information returned by the notification interface and will resend the notification at a certain frequency until it knows success (notification frequency 15s/15s/30s/3m/10m/20m/30m/30m/60m/3h/3h/3h/6h-total 24h4m).

5. Integrated SDK

Download to WeChat Open Platform SDK and DEMO And put business and lib from Demo into the project.

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using QRCoder;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using WxPayAPI;
using Microsoft.Extensions.Logging;
using System.Text;

namespace WxPay.Demo.Controllers
{
    public class PayController : Controller
    {
        private readonly ILogger<HomeController> _logger;

        public PayController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }

        /// <summary>
        ///Generate a direct payment url with a validity period of 2 hours.
        /// </summary>
        /// <returns></returns>
        public IActionResult Order()
        {
            WxPayData data = new WxPayData();
            data.SetValue("body", "Testing commodities");//Commodity description
            data.SetValue("attach", "test");//Additional data
            data.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());//Merchant order number, random string.
            data.SetValue("total_fee", Convert.ToInt32(0.01 * 100));//Total order amount in points.
            data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));//Transaction Start Time
            data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));//Deal End Time
            data.SetValue("goods_tag", "jjj");//Commodity Marking
            data.SetValue("trade_type", "NATIVE");//Transaction type
            data.SetValue("product_id", Guid.NewGuid().ToString("N"));//Commodity ID

            WxPayData result = WxPayApi.UnifiedOrder(data);//Call Unified Single Interface
            _logger.LogInformation("UnifiedOrder:\r\n" + result.ToXml());
            string url = result.GetValue("code_url").ToString();//Get 2D code links returned from unified single interface


            //Using QRCoder to generate two-dimensional codes
            var qrGenerator = new QRCodeGenerator();
            var qrCodeData = qrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q);
            var qrCode = new QRCode(qrCodeData);
            var image = qrCode.GetGraphic(6);
            using (var ms = new MemoryStream())
            {
                image.Save(ms, ImageFormat.Jpeg);
                return File(ms.ToArray(), "image/jpeg");
            }
        }

        private static object _locker = new object();
        public IActionResult Notify()
        {
            //1. Signature Verification
            //2. Determine if the order has been processed, if the processing returns directly to success.
            //3. Processing business platform orders
            //4. Return processing results to the WeChat background.
            WxPayData res = new WxPayData();

            lock (_locker)
            {
                var body = HttpContext.Request.BodyReader.AsStream();
                int count = 0;
                byte[] buffer = new byte[1024];
                StringBuilder builder = new StringBuilder();
                while ((count = body.Read(buffer, 0, 1024)) > 0)
                {
                    builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
                }
                var xml = builder.ToString();
                _logger.LogInformation("Notify:\r\n" + xml);

                try
                {
                    //Convert data formats and verify signatures
                    WxPayData data = new WxPayData();
                    var dics = data.FromXml(xml.ToString());
                    if (dics["return_code"] == "SUCCESS")
                    {
                        //Processing business platform orders...
                        var appid = dics["appid"];//Public Account ID
                        var mch_id = dics["mch_id"];//Business Number
                        var out_trade_no = dics["out_trade_no"];//Merchant Order Number
                        var total_fee = dics["total_fee"];//Total order amount in points.
                        var time_end = dics["time_end"];//Payment Completion Time
                        var transaction_id = dics["transaction_id"];//WeChat Payment Order Number

                        res.SetValue("return_code", "SUCCESS");//Return status code: SUCCESS/FAIL
                        res.SetValue("return_msg", "");//Return information
                    }
                    else
                    {
                        res.SetValue("return_code", "FAIL");
                        res.SetValue("return_msg", "");
                    }
                }
                catch (WxPayException ex)
                {
                    //If the signature is wrong, return the result to WeChat Payment Background immediately
                    res.SetValue("return_code", "FAIL");
                    res.SetValue("return_msg", ex.Message);
                }
            }

            return Content(res.ToXml(), "text/xml");
        }
    }
}

Keywords: ASP.NET .NET wechat

Added by akshay on Mon, 13 Sep 2021 19:54:45 +0300