Asp.net core wechat payment (1) [unified order apiv3]

Time:2021-6-18

Official references

Signature:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml

Signature generation:https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/qian-ming-sheng-cheng

Unified order interface:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_1.shtml

How to view certificate serial number:https://wechatpay-api.gitbook.io/wechatpay-api-v3/chang-jian-wen-ti/zheng-shu-xiang-guan#ru-he-cha-kan-zheng-shu-xu-lie-hao

Private key and certificate:https://wechatpay-api.gitbook.io/wechatpay-api-v3/ren-zheng/zheng-shu#sheng-ming-suo-shi-yong-de-zheng-shu

 

First of all, I declare that this is the interface provided for app payment!!! Other terminals are for reference only

1、 Signature

Generate signature

reference materialIt’s more detailed, and there are official documents, but the documents are incomplete, which leads to problems in my debugging program all the time. I ask for wechat’s helpUnified ordering interfaceBad request is always reported.

Signature generation referenceOfficial code, the code is as follows, which has the request interface I marked to report 400 error reason code

using System;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;

namespace HttpHandlerDemo
{
    //How to use it
    //Httpclient client = new httpclient (New HttpHandler ("{merchant number}", "{merchant certificate serial number}"));
    // ...
    // var response = client.GetAsync("https://api.mch.weixin.qq.com/v3/certificates");
    public class HttpHandler : DelegatingHandler
    {
        private readonly string merchantId;
        private readonly string serialNo;

        public HttpHandler(string merchantId, string merchantSerialNo)
        {
            InnerHandler = new HttpClientHandler();

            this.merchantId = merchantId;
            this.serialNo = merchantSerialNo;
        }

        protected async override Task SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            var auth = await BuildAuthAsync(request);
            string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
            request.Headers.Add("Authorization", value);
            request.Headers.Add("Accept", "application/json");// If this code is missing, the order interface request will fail and a bad request will be reported
            request.Headers.Add("User-Agent", "Mozilla/4.0 (compatible;  MSIE 6.0;  Windows NT 5.2; . NET CLR 1.0.3705;)");// If this code is missing, the order interface request will fail and a bad request will be reported

            return await base.SendAsync(request, cancellationToken);
        }

        protected async Task BuildAuthAsync(HttpRequestMessage request)
        {
            string method = request.Method.ToString();
            string body = "";
            if (method == "POST" || method == "PUT" || method == "PATCH")
            {
                var content = request.Content;
                body = await content.ReadAsStringAsync();// When debugging, make a breakpoint here to see what the value of body is. If it is inconsistent with the parameters you pass in, it means there is a problem. Please refer to my method
            }

            string uri = request.RequestUri.PathAndQuery;
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            string nonce = Path.GetRandomFileName();

            string message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            string signature = Sign(message);
            return $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
        }

        protected string Sign(string message)
        {
            //Note: private key does not include begin private key-----
            //The end private key is not included-----
            String privatekey = "{your private key}";
            byte[] keyData = Convert.FromBase64String(privateKey);
            using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob))
            using (RSACng rsa = new RSACng(cngKey))
            {
                byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
                return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
            }
        }
    }
}

2、 Unified order

usage method

var url = "https://api.mch.weixin.qq.com/v3/pay/transactions/app";
 var req = new GenerateOrderModelForWxPay
                {
                    appid = WxPayConst.appid,
                    mchid = WxPayConst.mchid,
                    Description = commodity name,
                    amount = new WxPayAmountModel
                    {
                        total = 1
                    },
                    out_trade_no = orderNumber,
                    notify_url = "https://xxx.com/api/WxPayCallback"
                };
Httpclient client = new httpclient (New HttpHandler ("{merchant number}", "{merchant certificate serial number}"));
//Get mode
var response = client.GetAsync("https://api.mch.weixin.qq.com/v3/certificates");

//Post mode
 var bodyJson = new StringContent(req.ToJson(), Encoding.UTF8, "application/json"); // It is necessary to pass parameters in this way, otherwise the parameters obtained when encrypting the signature are data in the form of \ \ U0, not the data passed, resulting in incorrect encryption results
var response = await client.PostAsync(url, bodyJson);

//Read unified order after the return results, so read out the direct result, or error reason, we must do so ah!!! How painful understanding, there will be specific error information.
var respStr = await response.Content.ReadAsStringAsync();// This includes prepay_ I don't know

3、 Attention

 You must see itInterface rulesI just didn’t read the instructions, which led me to fail to get through all day. Here are two screenshots

 

 

 

Recommended Today

The selector returned by ngrx store createselector performs one-step debugging of fetching logic

Test source code: import { Component } from ‘@angular/core’; import { createSelector } from ‘@ngrx/store’; export interface State { counter1: number; counter2: number; } export const selectCounter1 = (state: State) => state.counter1; export const selectCounter2 = (state: State) => state.counter2; export const selectTotal = createSelector( selectCounter1, selectCounter2, (counter1, counter2) => counter1 + counter2 ); // […]